Title: [282022] trunk
Revision
282022
Author
n...@apple.com
Date
2021-09-03 14:07:46 -0700 (Fri, 03 Sep 2021)

Log Message

AX: findModalNodes() and currentModalNode() should include modal <dialog>
https://bugs.webkit.org/show_bug.cgi?id=229815

Reviewed by Chris Fleizach.

Source/WebCore:

Test: accessibility/dialog-showModal.html

* accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::isModalElement const):
(WebCore::AXObjectCache::findModalNodes):
(WebCore::AXObjectCache::handleAttributeChange):
(WebCore::AXObjectCache::handleModalChange):
* accessibility/AXObjectCache.h:

LayoutTests:

* accessibility/dialog-showModal-expected.txt: Added.
* accessibility/dialog-showModal.html: Added.
* platform/win/TestExpectations:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (282021 => 282022)


--- trunk/LayoutTests/ChangeLog	2021-09-03 21:04:05 UTC (rev 282021)
+++ trunk/LayoutTests/ChangeLog	2021-09-03 21:07:46 UTC (rev 282022)
@@ -1,3 +1,14 @@
+2021-09-03  Tim Nguyen  <n...@apple.com>
+
+        AX: findModalNodes() and currentModalNode() should include modal <dialog>
+        https://bugs.webkit.org/show_bug.cgi?id=229815
+
+        Reviewed by Chris Fleizach.
+
+        * accessibility/dialog-showModal-expected.txt: Added.
+        * accessibility/dialog-showModal.html: Added.
+        * platform/win/TestExpectations:
+
 2021-09-03  Myles C. Maxfield  <mmaxfi...@apple.com>
 
         Test gardening after r281419

Added: trunk/LayoutTests/accessibility/dialog-showModal-expected.txt (0 => 282022)


--- trunk/LayoutTests/accessibility/dialog-showModal-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/accessibility/dialog-showModal-expected.txt	2021-09-03 21:07:46 UTC (rev 282022)
@@ -0,0 +1,36 @@
+This tests that dialog.showModal() makes other elements inert.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Dialog is hidden
+PASS backgroundAccessible() is true
+Dialog is displaying
+PASS backgroundAccessible() is false
+Dialog is not displaying
+PASS backgroundAccessible() is true
+PASS backgroundAccessible() is true
+PASS okButton.isIgnored is false
+Dialog is displaying
+PASS backgroundAccessible() is false
+PASS okButton.isIgnored is false
+Dialog is displaying and aria-hidden=true
+PASS backgroundAccessible() is false
+Dialog is displaying and aria-hidden=false
+PASS backgroundAccessible() is false
+Dialog is displaying and aria-modal=false
+PASS backgroundAccessible() is false
+Dialog is not displaying with opacity 0
+PASS backgroundAccessible() is false
+Dialog is displaying with opacity 1
+PASS backgroundAccessible() is false
+Dialog is removed from DOM
+PASS backgroundAccessible() is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Other page content with a dummy focusable element
+
+Display a dialog
+
+

Added: trunk/LayoutTests/accessibility/dialog-showModal.html (0 => 282022)


--- trunk/LayoutTests/accessibility/dialog-showModal.html	                        (rev 0)
+++ trunk/LayoutTests/accessibility/dialog-showModal.html	2021-09-03 21:07:46 UTC (rev 282022)
@@ -0,0 +1,109 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+
+<body id="body">
+
+<div id="background">
+    <p id="backgroundContent">Other page content with <a href="" dummy focusable element</a></p>
+    <p><a _onclick_="document.getElementById('dialog').showModal(); return false;" href="" role="button" id="displayButton">Display a dialog</a></p>
+</div>
+
+<div id="dialogParent" role="group">
+    <dialog id="dialog">
+        <h3>Just an example.</h3>
+        <button id="ok" _onclick_="document.getElementById('dialog').close();" class="close-button">OK</button>
+        <button _onclick_="document.getElementById('dialog').close();" class="close-button">Cancel</button>
+    </dialog>
+</div>
+
+<script>
+    description("This tests that dialog.showModal() makes other elements inert.");
+
+    if (window.accessibilityController) {
+        window.jsTestIsAsync = true;
+        
+        debug("Dialog is hidden");
+        shouldBeTrue("backgroundAccessible()");
+        document.getElementById("dialog").showModal();
+
+        // Background should be unaccessible after loading, since the
+        // dialog is displayed
+        debug("Dialog is displaying");
+        shouldBeFalse("backgroundAccessible()");
+
+        // Close the dialog, background should be accessible.
+        document.getElementById("ok").click();
+        setTimeout(async function() {
+            await waitFor(() => backgroundAccessible());
+            debug("Dialog is not displaying");
+            shouldBeTrue("backgroundAccessible()");
+
+            // Non modal <dialog> should allow interactions with background.
+            document.getElementById("dialog").show();
+            shouldBeTrue("backgroundAccessible()");
+            window.okButton = accessibilityController.accessibleElementById("ok");
+            shouldBeFalse("okButton.isIgnored");
+            document.getElementById("dialog").close();
+
+            // Click the display button, dialog shows and background becomes unaccessible.
+            document.getElementById("displayButton").click();
+            await waitFor(() => !backgroundAccessible());
+            debug("Dialog is displaying");
+            shouldBeFalse("backgroundAccessible()");
+            window.okButton = accessibilityController.accessibleElementById("ok");
+            shouldBeFalse("okButton.isIgnored");
+
+            // With the dialog displaying, test that aria-hidden and the opacity don't affect whether the background is accessible or not.
+            // Dialog is aria hidden
+            document.getElementById("dialog").setAttribute("aria-hidden", "true");
+            debug("Dialog is displaying and aria-hidden=true")
+            shouldBeFalse("backgroundAccessible()");
+
+            // Set aria-hidden=false.
+            document.getElementById("dialog").setAttribute("aria-hidden", "false");
+            debug("Dialog is displaying and aria-hidden=false");
+            shouldBeFalse("backgroundAccessible()");
+
+            // Set aria-modal=false.
+            document.getElementById("dialog").setAttribute("aria-modal", "false");
+            debug("Dialog is displaying and aria-modal=false");
+            shouldBeFalse("backgroundAccessible()");
+            document.getElementById("dialog").removeAttribute("aria-modal");
+
+            // Set opacity to 0 which should make the dialog invisible.
+            document.getElementById("dialog").style.opacity = 0;
+            debug("Dialog is not displaying with opacity 0");
+            shouldBeFalse("backgroundAccessible()");
+
+            // Set opacity to 1 which should make the dialog visible again.
+            document.getElementById("dialog").style.opacity = 1;
+            debug("Dialog is displaying with opacity 1");
+            shouldBeFalse("backgroundAccessible()");
+
+            // Test modal dialog is removed from DOM tree.
+            document.getElementById("dialog").remove();
+            await waitFor(() => backgroundAccessible());
+            debug("Dialog is removed from DOM");
+            shouldBeTrue("backgroundAccessible()");
+
+            finishJSTest();
+        }, 0);
+    }
+
+    function backgroundAccessible() {
+        var displayButton = accessibilityController.accessibleElementById("displayButton");
+        var backgroundContent = accessibilityController.accessibleElementById("backgroundContent");
+
+        if (!displayButton || !backgroundContent)
+            return false;
+
+        return !displayButton.isIgnored && !backgroundContent.isIgnored;
+    }
+</script>
+<script src=""
+</body>
+</html>

Modified: trunk/LayoutTests/platform/win/TestExpectations (282021 => 282022)


--- trunk/LayoutTests/platform/win/TestExpectations	2021-09-03 21:04:05 UTC (rev 282021)
+++ trunk/LayoutTests/platform/win/TestExpectations	2021-09-03 21:07:46 UTC (rev 282022)
@@ -1500,6 +1500,7 @@
 webkit.org/b/95405 accessibility/win/single-select-children.html [ Skip ]
 accessibility/file-upload-button-stringvalue.html
 webkit.org/b/97026 accessibility/file-upload-button-with-axpress.html [ Skip ] #  [ Timeout ]
+accessibility/dialog-showModal.html [ Skip ]
 
 # Color Well is not implemented:
 accessibility/color-well.html

Modified: trunk/Source/WebCore/ChangeLog (282021 => 282022)


--- trunk/Source/WebCore/ChangeLog	2021-09-03 21:04:05 UTC (rev 282021)
+++ trunk/Source/WebCore/ChangeLog	2021-09-03 21:07:46 UTC (rev 282022)
@@ -1,3 +1,19 @@
+2021-09-03  Tim Nguyen  <n...@apple.com>
+
+        AX: findModalNodes() and currentModalNode() should include modal <dialog>
+        https://bugs.webkit.org/show_bug.cgi?id=229815
+
+        Reviewed by Chris Fleizach.
+
+        Test: accessibility/dialog-showModal.html
+
+        * accessibility/AXObjectCache.cpp:
+        (WebCore::AXObjectCache::isModalElement const):
+        (WebCore::AXObjectCache::findModalNodes):
+        (WebCore::AXObjectCache::handleAttributeChange):
+        (WebCore::AXObjectCache::handleModalChange):
+        * accessibility/AXObjectCache.h:
+
 2021-09-03  Aditya Keerthi  <akeer...@apple.com>
 
         iframes should get an opaque background when the embedding element and embedded root color-schemes do not match

Modified: trunk/Source/WebCore/accessibility/AXObjectCache.cpp (282021 => 282022)


--- trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2021-09-03 21:04:05 UTC (rev 282021)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2021-09-03 21:07:46 UTC (rev 282022)
@@ -74,6 +74,7 @@
 #include "Frame.h"
 #include "HTMLAreaElement.h"
 #include "HTMLCanvasElement.h"
+#include "HTMLDialogElement.h"
 #include "HTMLImageElement.h"
 #include "HTMLInputElement.h"
 #include "HTMLLabelElement.h"
@@ -250,17 +251,20 @@
 #endif
 }
 
+bool AXObjectCache::isModalElement(Element& element) const
+{
+    bool hasDialogRole = nodeHasRole(&element, "dialog") || nodeHasRole(&element, "alertdialog");
+    bool isAriaModal = equalLettersIgnoringASCIICase(element.attributeWithoutSynchronization(aria_modalAttr), "true");
+
+    return (hasDialogRole && isAriaModal) || (is<HTMLDialogElement>(element) && downcast<HTMLDialogElement>(element).isModal());
+}
+
 void AXObjectCache::findModalNodes()
 {
-    // Traverse the DOM tree to look for the aria-modal=true nodes.
+    // Traverse the DOM tree to look for the aria-modal=true nodes or modal <dialog> elements.
     for (Element* element = ElementTraversal::firstWithin(document().rootNode()); element; element = ElementTraversal::nextIncludingPseudo(*element)) {
-        // Must have dialog or alertdialog role
-        if (!nodeHasRole(element, "dialog") && !nodeHasRole(element, "alertdialog"))
-            continue;
-        if (!equalLettersIgnoringASCIICase(element->attributeWithoutSynchronization(aria_modalAttr), "true"))
-            continue;
-
-        m_modalElementsSet.add(element);
+        if (isModalElement(*element))
+            m_modalElementsSet.add(element);
     }
 
     m_modalNodesInitialized = true;
@@ -268,12 +272,18 @@
 
 Element* AXObjectCache::currentModalNode()
 {
-    // There might be multiple nodes with aria-modal=true set.
+    // There might be multiple modal dialog nodes.
     // We use this function to pick the one we want.
     m_currentModalElement = nullptr;
     if (m_modalElementsSet.isEmpty())
         return nullptr;
 
+    // Pick the document active modal <dialog> element if it exists.
+    if (Element* activeModalDialog = document().activeModalDialog()) {
+        ASSERT(m_modalElementsSet.contains(activeModalDialog));
+        return activeModalDialog;
+    }
+
     // If any of the modal nodes contains the keyboard focus, we want to pick that one.
     // If not, we want to pick the last visible dialog in the DOM.
     RefPtr<Element> focusedElement = document().focusedElement();
@@ -1802,7 +1812,12 @@
     else if (attrName == idAttr)
         updateIsolatedTree(get(element), AXObjectCache::AXIdAttributeChanged);
 #endif
+    else if (attrName == openAttr && is<HTMLDialogElement>(*element)) {
+        deferModalChange(element);
+        recomputeIsIgnored(element->parentNode());
+    }
 
+
     if (!attrName.localName().string().startsWith("aria-"))
         return;
 
@@ -1849,7 +1864,7 @@
 
 void AXObjectCache::handleModalChange(Element& element)
 {
-    if (!nodeHasRole(&element, "dialog") && !nodeHasRole(&element, "alertdialog"))
+    if (!is<HTMLDialogElement>(element) && !nodeHasRole(&element, "dialog") && !nodeHasRole(&element, "alertdialog"))
         return;
 
     stopCachingComputedObjectAttributes();
@@ -1857,7 +1872,7 @@
     if (!m_modalNodesInitialized)
         findModalNodes();
 
-    if (equalLettersIgnoringASCIICase(element.attributeWithoutSynchronization(aria_modalAttr), "true")) {
+    if (isModalElement(element)) {
         // Add the newly modified node to the modal nodes set.
         // We will recompute the current valid aria modal node in modalNode() when this node is not visible.
         m_modalElementsSet.add(&element);

Modified: trunk/Source/WebCore/accessibility/AXObjectCache.h (282021 => 282022)


--- trunk/Source/WebCore/accessibility/AXObjectCache.h	2021-09-03 21:04:05 UTC (rev 282021)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.h	2021-09-03 21:07:46 UTC (rev 282022)
@@ -472,7 +472,8 @@
     void handleAriaExpandedChange(Node*);
     void handleFocusedUIElementChanged(Node* oldFocusedNode, Node* newFocusedNode);
 
-    // aria-modal related
+    // aria-modal or modal <dialog> related
+    bool isModalElement(Element&) const;
     void findModalNodes();
     Element* currentModalNode();
     bool isNodeVisible(Node*) const;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to