Skip to content

Commit

Permalink
AX: aria-hidden=true should be ignored on the body and html elements
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=269523
rdar://123049663

Reviewed by Chris Fleizach.

To prevent authors from hiding all content from assistive technologies, aria-hidden should not be respected on document
root elements (`html`, `body`, or top-level `svg`s).

w3c/aria#1880

* LayoutTests/accessibility/body-element-aria-hidden-expected.txt: Added.
* LayoutTests/accessibility/body-element-aria-hidden.html: Added.
* LayoutTests/accessibility/html-element-aria-hidden-expected.txt: Added.
* LayoutTests/accessibility/html-element-aria-hidden.html: Added.
* LayoutTests/platform/ios/TestExpectations: Enable new tests.
* Source/WebCore/accessibility/AXCoreObject.h:
* Source/WebCore/accessibility/AccessibilityObject.cpp:
(WebCore::AccessibilityObject::isARIAHidden const):
(WebCore::AccessibilityObject::tagName const):
(WebCore::AccessibilityObject::setIsIgnoredFromParentDataForChild):
* Source/WebCore/accessibility/AccessibilityObject.h:
* Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp:
(WebCore::AccessibilityObjectAtspi::attributes const):
* Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp:
(WebCore::AXIsolatedObject::tagName const): Deleted.
* Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h:
  • Loading branch information
twilco authored and JonWBedard committed Apr 15, 2024
1 parent 993b286 commit 6cedd71
Show file tree
Hide file tree
Showing 11 changed files with 74 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
This test ensures that aria-hidden='true' is not respected on the body element.

PASS: accessibilityController.accessibleElementById('button').role.toLowerCase().includes('button') === true

PASS successfullyParsed is true

TEST COMPLETE
Submit
21 changes: 21 additions & 0 deletions LayoutTests/accessibility/body-element-aria-hidden.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!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 aria-hidden="true">

<button id="button">Submit</button>

<script>
var output = "This test ensures that aria-hidden='true' is not respected on the body element.\n\n";

if (window.accessibilityController) {
output += expect("accessibilityController.accessibleElementById('button').role.toLowerCase().includes('button')", "true");
debug(output);
}
</script>
</body>
</html>

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
This test ensures that aria-hidden='true' is not respected on the html element.

PASS: accessibilityController.accessibleElementById('button').role.toLowerCase().includes('button') === true

PASS successfullyParsed is true

TEST COMPLETE
Submit
21 changes: 21 additions & 0 deletions LayoutTests/accessibility/html-element-aria-hidden.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html aria-hidden="true">
<head>
<script src="../resources/accessibility-helper.js"></script>
<script src="../resources/js-test.js"></script>
</head>
<body>

<button id="button">Submit</button>

<script>
var output = "This test ensures that aria-hidden='true' is not respected on the html element.\n\n";

if (window.accessibilityController) {
output += expect("accessibilityController.accessibleElementById('button').role.toLowerCase().includes('button')", "true");
debug(output);
}
</script>
</body>
</html>

2 changes: 2 additions & 0 deletions LayoutTests/platform/ios/TestExpectations
Original file line number Diff line number Diff line change
Expand Up @@ -2300,6 +2300,7 @@ accessibility/aria-braillelabel.html [ Pass ]
accessibility/aria-brailleroledescription.html [ Pass ]
accessibility/aria-checked-mixed-value.html [ Pass ]
accessibility/aria-describedby-on-input.html [ Pass ]
accessibility/body-element-aria-hidden.html [ Pass ]
accessibility/display-contents/aria-hidden.html [ Pass ]
accessibility/aria-multiline.html [ Pass ]
accessibility/aria-readonly-updates-after-dynamic-change.html [ Pass ]
Expand All @@ -2325,6 +2326,7 @@ accessibility/empty-text-under-element-cached.html [ Pass ]
accessibility/heading-level.html [ Pass ]
accessibility/hidden-label.html [ Pass ]
accessibility/hidden-slot.html [ Pass ]
accessibility/html-element-aria-hidden.html [ Pass ]
accessibility/html5-required-attribute.html [ Pass ]
accessibility/iframe-tree-update-with-dirty-layout.html [ Pass ]
accessibility/iframe-with-role.html [ Pass ]
Expand Down
1 change: 0 additions & 1 deletion Source/WebCore/accessibility/AXCoreObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -1272,7 +1272,6 @@ class AXCoreObject : public ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr<AXCo
bool isAncestorOfObject(const AXCoreObject*) const;

virtual String nameAttribute() const = 0;
virtual AtomString tagName() const = 0;

virtual std::optional<SimpleRange> simpleRange() const = 0;
virtual VisiblePositionRange visiblePositionRange() const = 0;
Expand Down
19 changes: 12 additions & 7 deletions Source/WebCore/accessibility/AccessibilityObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3987,12 +3987,19 @@ bool AccessibilityObject::isARIAHidden() const
return false;

auto* node = this->node();
auto* element = dynamicDowncast<Element>(node);
AtomString tag = element ? element->localName() : nullAtom();
// https://github.com/w3c/aria/pull/1880
// To prevent authors from hiding all content from assistive technology users, do not respect
// aria-hidden on html, body, or document-root svg elements.
if (tag == bodyTag || tag == htmlTag || (tag == SVGNames::svgTag && !element->parentNode()))
return false;

if (auto* assignedSlot = node ? node->assignedSlot() : nullptr) {
if (equalLettersIgnoringASCIICase(assignedSlot->attributeWithDefaultARIA(aria_hiddenAttr), "true"_s))
return true;
}

return equalLettersIgnoringASCIICase(getAttribute(aria_hiddenAttr), "true"_s);
return element && equalLettersIgnoringASCIICase(element->attributeWithDefaultARIA(aria_hiddenAttr), "true"_s);
}

// ARIA component of hidden definition.
Expand Down Expand Up @@ -4174,10 +4181,8 @@ AccessibilityObject* AccessibilityObject::radioGroupAncestor() const

AtomString AccessibilityObject::tagName() const
{
if (Element* element = this->element())
return element->localName();

return nullAtom();
auto* element = this->element();
return element ? element->localName() : nullAtom();
}

bool AccessibilityObject::isStyleFormatGroup() const
Expand Down Expand Up @@ -4441,7 +4446,7 @@ void AccessibilityObject::setIsIgnoredFromParentDataForChild(AccessibilityObject

AccessibilityIsIgnoredFromParentData result = AccessibilityIsIgnoredFromParentData(this);
if (!m_isIgnoredFromParentData.isNull()) {
result.isAXHidden = (m_isIgnoredFromParentData.isAXHidden || equalLettersIgnoringASCIICase(child->getAttribute(aria_hiddenAttr), "true"_s)) && !child->isFocused();
result.isAXHidden = (m_isIgnoredFromParentData.isAXHidden || child->isARIAHidden());
result.isPresentationalChildOfAriaRole = m_isIgnoredFromParentData.isPresentationalChildOfAriaRole || ariaRoleHasPresentationalChildren();
result.isDescendantOfBarrenParent = m_isIgnoredFromParentData.isDescendantOfBarrenParent || !canHaveChildren();
} else {
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/accessibility/AccessibilityObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ class AccessibilityObject : public AXCoreObject, public CanMakeWeakPtr<Accessibi
String nameAttribute() const final;
int getIntegralAttribute(const QualifiedName&) const;
bool hasTagName(const QualifiedName&) const;
AtomString tagName() const override;
AtomString tagName() const;
bool hasDisplayContents() const;

std::optional<SimpleRange> simpleRange() const override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -864,7 +864,7 @@ HashMap<String, String> AccessibilityObjectAtspi::attributes() const

RefPtr liveObject = dynamicDowncast<AccessibilityObject>(m_coreObject);

String tagName = m_coreObject->tagName();
String tagName = liveObject->tagName();
if (!tagName.isEmpty())
map.add("tag"_s, tagName);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1377,12 +1377,6 @@ void AXIsolatedObject::decrement()
});
}

AtomString AXIsolatedObject::tagName() const
{
ASSERT_NOT_REACHED();
return AtomString();
}

bool AXIsolatedObject::isAccessibilityRenderObject() const
{
ASSERT_NOT_REACHED();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,6 @@ class AXIsolatedObject final : public AXCoreObject {
std::optional<AccessibilityChildrenVector> selectedChildren() final;
void setSelectedChildren(const AccessibilityChildrenVector&) final;
AccessibilityChildrenVector visibleChildren() final { return tree()->objectsForIDs(vectorAttributeValue<AXID>(AXPropertyName::VisibleChildren)); }
AtomString tagName() const final;
void setChildrenIDs(Vector<AXID>&&);
void updateChildrenIfNecessary() final;
bool isDetachedFromParent() final;
Expand Down

0 comments on commit 6cedd71

Please sign in to comment.