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;