diff --git a/LayoutTests/accessibility/body-element-aria-hidden-expected.txt b/LayoutTests/accessibility/body-element-aria-hidden-expected.txt
new file mode 100644
index 0000000000000..bb6433dc4b948
--- /dev/null
+++ b/LayoutTests/accessibility/body-element-aria-hidden-expected.txt
@@ -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
diff --git a/LayoutTests/accessibility/body-element-aria-hidden.html b/LayoutTests/accessibility/body-element-aria-hidden.html
new file mode 100644
index 0000000000000..c5cfd67d1ae40
--- /dev/null
+++ b/LayoutTests/accessibility/body-element-aria-hidden.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LayoutTests/accessibility/html-element-aria-hidden-expected.txt b/LayoutTests/accessibility/html-element-aria-hidden-expected.txt
new file mode 100644
index 0000000000000..b5a6333b8cbde
--- /dev/null
+++ b/LayoutTests/accessibility/html-element-aria-hidden-expected.txt
@@ -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
diff --git a/LayoutTests/accessibility/html-element-aria-hidden.html b/LayoutTests/accessibility/html-element-aria-hidden.html
new file mode 100644
index 0000000000000..f94bbb86aaae5
--- /dev/null
+++ b/LayoutTests/accessibility/html-element-aria-hidden.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LayoutTests/platform/ios/TestExpectations b/LayoutTests/platform/ios/TestExpectations
index f4d56e2e15c25..57aca359716c8 100644
--- a/LayoutTests/platform/ios/TestExpectations
+++ b/LayoutTests/platform/ios/TestExpectations
@@ -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 ]
@@ -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 ]
diff --git a/Source/WebCore/accessibility/AXCoreObject.h b/Source/WebCore/accessibility/AXCoreObject.h
index 0f88f8dbbcab9..0a63e482900ba 100644
--- a/Source/WebCore/accessibility/AXCoreObject.h
+++ b/Source/WebCore/accessibility/AXCoreObject.h
@@ -1272,7 +1272,6 @@ class AXCoreObject : public ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr simpleRange() const = 0;
virtual VisiblePositionRange visiblePositionRange() const = 0;
diff --git a/Source/WebCore/accessibility/AccessibilityObject.cpp b/Source/WebCore/accessibility/AccessibilityObject.cpp
index 0bce8a69d230b..15c30699caeb0 100644
--- a/Source/WebCore/accessibility/AccessibilityObject.cpp
+++ b/Source/WebCore/accessibility/AccessibilityObject.cpp
@@ -3987,12 +3987,19 @@ bool AccessibilityObject::isARIAHidden() const
return false;
auto* node = this->node();
+ auto* element = dynamicDowncast(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.
@@ -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
@@ -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 {
diff --git a/Source/WebCore/accessibility/AccessibilityObject.h b/Source/WebCore/accessibility/AccessibilityObject.h
index 6b3efc9dafafb..187d866d37253 100644
--- a/Source/WebCore/accessibility/AccessibilityObject.h
+++ b/Source/WebCore/accessibility/AccessibilityObject.h
@@ -543,7 +543,7 @@ class AccessibilityObject : public AXCoreObject, public CanMakeWeakPtr simpleRange() const override;
diff --git a/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp b/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp
index 76584f84b09d0..4967939cb8325 100644
--- a/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp
+++ b/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp
@@ -864,7 +864,7 @@ HashMap AccessibilityObjectAtspi::attributes() const
RefPtr liveObject = dynamicDowncast(m_coreObject);
- String tagName = m_coreObject->tagName();
+ String tagName = liveObject->tagName();
if (!tagName.isEmpty())
map.add("tag"_s, tagName);
diff --git a/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp b/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp
index a5fb14f02950b..2e5f6917c547e 100644
--- a/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp
+++ b/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp
@@ -1377,12 +1377,6 @@ void AXIsolatedObject::decrement()
});
}
-AtomString AXIsolatedObject::tagName() const
-{
- ASSERT_NOT_REACHED();
- return AtomString();
-}
-
bool AXIsolatedObject::isAccessibilityRenderObject() const
{
ASSERT_NOT_REACHED();
diff --git a/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h b/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h
index a89b6b15b4941..728f52db3a4d0 100644
--- a/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h
+++ b/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h
@@ -338,7 +338,6 @@ class AXIsolatedObject final : public AXCoreObject {
std::optional selectedChildren() final;
void setSelectedChildren(const AccessibilityChildrenVector&) final;
AccessibilityChildrenVector visibleChildren() final { return tree()->objectsForIDs(vectorAttributeValue(AXPropertyName::VisibleChildren)); }
- AtomString tagName() const final;
void setChildrenIDs(Vector&&);
void updateChildrenIfNecessary() final;
bool isDetachedFromParent() final;