tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit a8d63cecdddfc8246f394d2f33ffa3a9c7483c4e
parent a7e931db6dda646332fba4f4a22a62dc4bcd3660
Author: Eitan Isaacson <eitan@monotonous.org>
Date:   Tue,  4 Nov 2025 18:55:53 +0000

Bug 1998229 - Push relations cache when dependend IDs change ID. r=morgan.

Differential Revision: https://phabricator.services.mozilla.com/D271266

Diffstat:
Maccessible/generic/DocAccessible.cpp | 22++++++++++++++++++++--
Maccessible/generic/DocAccessible.h | 3++-
Maccessible/tests/browser/relations/head.js | 42++++++++++++++++++++++++++++++------------
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, host, [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); } }