commit 0199c1fad16bf7c05d1f2b2fcebef161ebff6bee
parent e22b182d7cba25f380db7dad70877303066af9dc
Author: Eitan Isaacson <eitan@monotonous.org>
Date: Tue, 4 Nov 2025 22:49:47 +0000
Bug 1998229 - Push relations cache when dependend IDs change ID. r=morgan.
Differential Revision: https://phabricator.services.mozilla.com/D271266
Diffstat:
3 files changed, 52 insertions(+), 15 deletions(-)
diff --git a/accessible/generic/DocAccessible.cpp b/accessible/generic/DocAccessible.cpp
@@ -444,7 +444,7 @@ void DocAccessible::QueueCacheUpdate(LocalAccessible* aAcc, uint64_t aNewDomain,
}
void DocAccessible::QueueCacheUpdateForDependentRelations(
- LocalAccessible* aAcc) {
+ LocalAccessible* aAcc, const nsAttrValue* aOldId) {
if (!mIPCDoc || !aAcc || !aAcc->IsInDocument() || aAcc->IsDefunct()) {
return;
}
@@ -466,6 +466,24 @@ void DocAccessible::QueueCacheUpdateForDependentRelations(
QueueCacheUpdate(relatedAcc, CacheDomain::Relations);
}
+ if (aOldId) {
+ // If we have an old ID, we need to update any accessibles that depended on
+ // that ID as well.
+ nsAutoString id;
+ aOldId->ToString(id);
+ if (!id.IsEmpty()) {
+ auto* providers = GetRelProviders(el, id);
+ if (providers) {
+ for (auto& provider : *providers) {
+ if (LocalAccessible* oldRelatedAcc =
+ GetAccessible(provider->mContent)) {
+ QueueCacheUpdate(oldRelatedAcc, CacheDomain::Relations);
+ }
+ }
+ }
+ }
+ }
+
if (const nsIFrame* anchorFrame = nsCoreUtils::GetAnchorForPositionedFrame(
mPresShell, aAcc->GetFrame())) {
// If this accessible is anchored, retrieve the anchor and update its
@@ -945,7 +963,7 @@ void DocAccessible::AttributeChanged(dom::Element* aElement,
RelocateARIAOwnedIfNeeded(elm);
ARIAActiveDescendantIDMaybeMoved(accessible);
QueueCacheUpdate(accessible, CacheDomain::DOMNodeIDAndClass);
- QueueCacheUpdateForDependentRelations(accessible);
+ QueueCacheUpdateForDependentRelations(accessible, aOldValue);
}
// The activedescendant universal property redirects accessible focus events
diff --git a/accessible/generic/DocAccessible.h b/accessible/generic/DocAccessible.h
@@ -129,7 +129,8 @@ class DocAccessible : public HyperTextAccessible,
* We call this when we observe an ID mutation or when an acc is bound
* to its document.
*/
- void QueueCacheUpdateForDependentRelations(LocalAccessible* aAcc);
+ void QueueCacheUpdateForDependentRelations(
+ LocalAccessible* aAcc, const nsAttrValue* aOldId = nullptr);
/**
* Returns true if the instance has shutdown.
diff --git a/accessible/tests/browser/relations/head.js b/accessible/tests/browser/relations/head.js
@@ -159,22 +159,32 @@ async function testRelated(
},
{
desc: "Set attribute",
- attrs: [{ key: attr, value: "dependant1" }],
+ attrs: [{ id: "host", key: attr, value: "dependant1" }],
expected: [host, null, dependant1],
},
{
desc: "Change attribute",
- attrs: [{ key: attr, value: "dependant2" }],
+ attrs: [{ id: "host", key: attr, value: "dependant2" }],
expected: [null, host, dependant2],
},
{
desc: "Change attribute to multiple targets",
- attrs: [{ key: attr, value: "dependant1 dependant2" }],
+ attrs: [{ id: "host", key: attr, value: "dependant1 dependant2" }],
+ expected: [host, host, [dependant1, dependant2]],
+ },
+ {
+ desc: "Change 'dependent2' id to 'invalid'",
+ attrs: [{ id: "dependant2", key: "id", value: "invalid" }],
+ expected: [host, null, dependant1],
+ },
+ {
+ desc: "Change 'invalid' id back to 'dependent2'",
+ attrs: [{ id: "invalid", key: "id", value: "dependant2" }],
expected: [host, host, [dependant1, dependant2]],
},
{
desc: "Remove attribute",
- attrs: [{ key: attr }],
+ attrs: [{ id: "host", key: attr }],
expected: [null, null, null],
},
];
@@ -184,24 +194,32 @@ async function testRelated(
tests = tests.concat([
{
desc: "Set reflected attribute",
- reflectedattr: [{ key: reflectedAttrName, value: ["dependant1"] }],
+ reflectedattr: [
+ { id: "host", key: reflectedAttrName, value: ["dependant1"] },
+ ],
expected: [host, null, dependant1],
},
{
desc: "Change reflected attribute",
- reflectedattr: [{ key: reflectedAttrName, value: ["dependant2"] }],
+ reflectedattr: [
+ { id: "host", key: reflectedAttrName, value: ["dependant2"] },
+ ],
expected: [null, host, dependant2],
},
{
desc: "Change reflected attribute to multiple targets",
reflectedattr: [
- { key: reflectedAttrName, value: ["dependant2", "dependant1"] },
+ {
+ id: "host",
+ key: reflectedAttrName,
+ value: ["dependant2", "dependant1"],
+ },
],
expected: [host, host, [dependant1, dependant2]],
},
{
desc: "Remove reflected attribute",
- reflectedattr: [{ key: reflectedAttrName, value: null }],
+ reflectedattr: [{ id: "host", key: reflectedAttrName, value: null }],
expected: [null, null, null],
},
]);
@@ -211,12 +229,12 @@ async function testRelated(
info(desc);
if (attrs) {
- for (let { key, value } of attrs) {
- await invokeSetAttribute(browser, "host", key, value);
+ for (let { id, key, value } of attrs) {
+ await invokeSetAttribute(browser, id, key, value);
}
} else if (reflectedattr) {
- for (let { key, value } of reflectedattr) {
- await invokeSetReflectedElementsAttribute(browser, "host", key, value);
+ for (let { id, key, value } of reflectedattr) {
+ await invokeSetReflectedElementsAttribute(browser, id, key, value);
}
}