tor-browser

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

commit 3b389fdd62e93b624a2a01b240e30556c059f389
parent 5cc2a12756a9de2d4352f28ce12744dad66b15f0
Author: Alice Boxhall <95208+alice@users.noreply.github.com>
Date:   Wed, 24 Dec 2025 13:39:25 +0000

Bug 1984685 - Refactor: consistently return Maybe<nsTArray<RefPtr<Element>>> when getting attr-associated elements, and key AttrRelProviders on nsAtom rather than nsString. r=dom-core,morgan,Jamie,smaug

The existing `Element::GetAttrAssociatedElements()` and its internal lambda (which the subsequent change promotes into the `GetAttrAssociatedElementsInternal()` method, in order to use it as the internal "source of truth" method) already used arrays of `RefPtrs`, since the former interacts with scripting. In the subsequent change, since the `GetAttrAssociatedElementsInternal()` method which I adapted from the original lambda is used both by the bindings-exposed `GetAttrAssociatedElementsForBindings()` and in `AssociatedElementsIterator()`, I thought it was more straightforward to adapt `AssociatedElementsIterator` to use the array of `RefPtrs` rather than unpack the raw pointers each time, but I'm happy to modify it if this will be too slow or memory-intensive.

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

Diffstat:
Maccessible/base/AccIterator.cpp | 11++++++-----
Maccessible/base/AccIterator.h | 2+-
Maccessible/base/nsAccUtils.cpp | 11+++++------
Maccessible/base/nsAccUtils.h | 4++--
Maccessible/base/nsAccessibilityService.cpp | 3+--
Maccessible/generic/DocAccessible-inl.h | 6+++---
Maccessible/generic/DocAccessible.cpp | 72+++++++++++++++++++++++++++++++++++++-----------------------------------
Maccessible/generic/DocAccessible.h | 11+++++------
Mdom/base/Element.cpp | 9++++++---
Mdom/base/Element.h | 4++--
Mdom/html/ElementInternals.cpp | 18+++++++++---------
Mdom/html/ElementInternals.h | 2+-
12 files changed, 78 insertions(+), 75 deletions(-)

diff --git a/accessible/base/AccIterator.cpp b/accessible/base/AccIterator.cpp @@ -80,9 +80,8 @@ RelatedAccIterator::RelatedAccIterator(DocAccessible* aDocument, mProviders(nullptr), mIndex(0), mIsWalkingDependentElements(false) { - nsAutoString id; - if (aDependentContent->IsElement() && - aDependentContent->AsElement()->GetAttr(nsGkAtoms::id, id)) { + if (!aDependentContent->IsElement()) return; + if (nsAtom* id = aDependentContent->GetID()) { mProviders = mDocument->GetRelProviders(aDependentContent->AsElement(), id); } } @@ -254,8 +253,10 @@ AssociatedElementsIterator::AssociatedElementsIterator(DocAccessible* aDoc, mContent->AsElement()->GetAttr(aIDRefsAttr, mIDs); if (mIDs.IsEmpty() && (aria::AttrCharacteristicsFor(aIDRefsAttr) & ATTR_REFLECT_ELEMENTS)) { - nsAccUtils::GetARIAElementsAttr(mContent->AsElement(), aIDRefsAttr, - mElements); + if (auto elements = nsAccUtils::GetARIAElementsAttr(mContent->AsElement(), + aIDRefsAttr)) { + mElements.SwapElements(*elements); + } } } } diff --git a/accessible/base/AccIterator.h b/accessible/base/AccIterator.h @@ -245,7 +245,7 @@ class AssociatedElementsIterator : public AccIterable { nsIContent* mContent; DocAccessible* mDoc; nsAString::index_type mCurrIdx; - nsTArray<dom::Element*> mElements; + nsTArray<RefPtr<dom::Element>> mElements; uint32_t mElemIdx; }; diff --git a/accessible/base/nsAccUtils.cpp b/accessible/base/nsAccUtils.cpp @@ -579,20 +579,19 @@ const nsAttrValue* nsAccUtils::GetARIAAttr(dom::Element* aElement, return defaults->GetAttr(aName, kNameSpaceID_None); } -bool nsAccUtils::GetARIAElementsAttr(dom::Element* aElement, nsAtom* aName, - nsTArray<dom::Element*>& aElements) { +Maybe<nsTArray<RefPtr<dom::Element>>> nsAccUtils::GetARIAElementsAttr( + dom::Element* aElement, nsAtom* aName) { if (aElement->HasAttr(aName)) { - aElement->GetExplicitlySetAttrElements(aName, aElements); - return true; + return aElement->GetExplicitlySetAttrElements(aName); } if (auto* element = nsGenericHTMLElement::FromNode(aElement)) { if (auto* internals = element->GetInternals()) { - return internals->GetAttrElements(aName, aElements); + return internals->GetAttrElements(aName); } } - return false; + return Nothing(); } bool nsAccUtils::ARIAAttrValueIs(dom::Element* aElement, const nsAtom* aName, diff --git a/accessible/base/nsAccUtils.h b/accessible/base/nsAccUtils.h @@ -289,8 +289,8 @@ class nsAccUtils { nsAString& aResult); static const nsAttrValue* GetARIAAttr(dom::Element* aElement, const nsAtom* aName); - static bool GetARIAElementsAttr(dom::Element* aElement, nsAtom* aName, - nsTArray<dom::Element*>& aElements); + static Maybe<nsTArray<RefPtr<dom::Element>>> GetARIAElementsAttr( + dom::Element* aElement, nsAtom* aName); static bool ARIAAttrValueIs(dom::Element* aElement, const nsAtom* aName, const nsAString& aValue, nsCaseTreatment aCaseSensitive); diff --git a/accessible/base/nsAccessibilityService.cpp b/accessible/base/nsAccessibilityService.cpp @@ -242,8 +242,7 @@ static bool MustBeAccessible(nsIContent* aContent, DocAccessible* aDocument) { // If the given ID is referred by relation attribute then create an // Accessible for it. - nsAutoString id; - if (nsCoreUtils::GetID(aContent, id) && !id.IsEmpty()) { + if (nsAtom* id = aContent->GetID()) { return aDocument->IsDependentID(aContent->AsElement(), id); } } diff --git a/accessible/generic/DocAccessible-inl.h b/accessible/generic/DocAccessible-inl.h @@ -131,7 +131,7 @@ inline void DocAccessible::CreateSubtree(LocalAccessible* aChild) { } inline DocAccessible::AttrRelProviders* DocAccessible::GetRelProviders( - dom::Element* aElement, const nsAString& aID) const { + dom::Element* aElement, nsAtom* aID) const { DependentIDsHashtable* hash = mDependentIDsHashes.Get( aElement->GetUncomposedDocOrConnectedShadowRoot()); if (hash) { @@ -141,7 +141,7 @@ inline DocAccessible::AttrRelProviders* DocAccessible::GetRelProviders( } inline DocAccessible::AttrRelProviders* DocAccessible::GetOrCreateRelProviders( - dom::Element* aElement, const nsAString& aID) { + dom::Element* aElement, nsAtom* aID) { dom::DocumentOrShadowRoot* docOrShadowRoot = aElement->GetUncomposedDocOrConnectedShadowRoot(); DependentIDsHashtable* hash = @@ -151,7 +151,7 @@ inline DocAccessible::AttrRelProviders* DocAccessible::GetOrCreateRelProviders( } inline void DocAccessible::RemoveRelProvidersIfEmpty(dom::Element* aElement, - const nsAString& aID) { + nsAtom* aID) { dom::DocumentOrShadowRoot* docOrShadowRoot = aElement->GetUncomposedDocOrConnectedShadowRoot(); DependentIDsHashtable* hash = mDependentIDsHashes.Get(docOrShadowRoot); diff --git a/accessible/generic/DocAccessible.cpp b/accessible/generic/DocAccessible.cpp @@ -468,19 +468,17 @@ void DocAccessible::QueueCacheUpdateForDependentRelations( QueueCacheUpdate(relatedAcc, CacheDomain::Relations); } - if (aOldId) { + if (aOldId && !aOldId->IsEmptyString()) { // 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); - } + MOZ_ASSERT(aOldId->Type() == nsAttrValue::eAtom); + RefPtr<nsAtom> id = aOldId->GetAtomValue(); + auto* providers = GetRelProviders(el, id); + if (providers) { + for (auto& provider : *providers) { + if (LocalAccessible* oldRelatedAcc = + GetAccessible(provider->mContent)) { + QueueCacheUpdate(oldRelatedAcc, CacheDomain::Relations); } } } @@ -1670,8 +1668,8 @@ void DocAccessible::ProcessInvalidationList() { if (container) { // Check if the node is a target of aria-owns, and if so, don't process // it here and let DoARIAOwnsRelocation process it. - AttrRelProviders* list = GetRelProviders( - content->AsElement(), nsDependentAtomString(content->GetID())); + AttrRelProviders* list = + GetRelProviders(content->AsElement(), content->GetID()); bool shouldProcess = !!list; if (shouldProcess) { for (uint32_t idx = 0; idx < list->Length(); idx++) { @@ -1931,7 +1929,9 @@ void DocAccessible::AddDependentIDsFor(LocalAccessible* aRelProvider, const nsDependentSubstring id = iter.NextID(); if (id.IsEmpty()) break; - AttrRelProviders* providers = GetOrCreateRelProviders(relProviderEl, id); + RefPtr<nsAtom> idAtom = NS_Atomize(id); + AttrRelProviders* providers = + GetOrCreateRelProviders(relProviderEl, idAtom); if (providers) { AttrRelProvider* provider = new AttrRelProvider(relAttr, relProviderEl); if (provider) { @@ -1974,7 +1974,9 @@ void DocAccessible::RemoveDependentIDsFor(LocalAccessible* aRelProvider, const nsDependentSubstring id = iter.NextID(); if (id.IsEmpty()) break; - AttrRelProviders* providers = GetRelProviders(relProviderElm, id); + RefPtr<nsAtom> idAtom = NS_Atomize(id); + AttrRelProviders* providers = + GetOrCreateRelProviders(relProviderElm, idAtom); if (providers) { providers->RemoveElementsBy( [relAttr, relProviderElm](const auto& provider) { @@ -1982,7 +1984,7 @@ void DocAccessible::RemoveDependentIDsFor(LocalAccessible* aRelProvider, provider->mContent == relProviderElm; }); - RemoveRelProvidersIfEmpty(relProviderElm, id); + RemoveRelProvidersIfEmpty(relProviderElm, idAtom); } } @@ -2023,13 +2025,13 @@ void DocAccessible::AddDependentElementsFor(LocalAccessible* aRelProvider, if (aRelAttr && aRelAttr != attr) { continue; } - nsTArray<dom::Element*> elements; - nsAccUtils::GetARIAElementsAttr(providerEl, attr, elements); - for (dom::Element* targetEl : elements) { - AttrRelProviders& providers = - mDependentElementsMap.LookupOrInsert(targetEl); - AttrRelProvider* provider = new AttrRelProvider(attr, providerEl); - providers.AppendElement(provider); + if (auto elements = nsAccUtils::GetARIAElementsAttr(providerEl, attr)) { + for (auto targetEl : *elements) { + AttrRelProviders& providers = + mDependentElementsMap.LookupOrInsert(targetEl); + AttrRelProvider* provider = new AttrRelProvider(attr, providerEl); + providers.AppendElement(provider); + } } // If the relation attribute was given, we've already handled it. We don't // have anything else to check. @@ -2075,16 +2077,17 @@ void DocAccessible::RemoveDependentElementsFor(LocalAccessible* aRelProvider, if (aRelAttr && aRelAttr != attr) { continue; } - nsTArray<dom::Element*> elements; - nsAccUtils::GetARIAElementsAttr(providerEl, attr, elements); - for (dom::Element* targetEl : elements) { - if (auto providers = mDependentElementsMap.Lookup(targetEl)) { - providers.Data().RemoveElementsBy([attr, - providerEl](const auto& provider) { - return provider->mRelAttr == attr && provider->mContent == providerEl; - }); - if (providers.Data().IsEmpty()) { - providers.Remove(); + if (auto elements = nsAccUtils::GetARIAElementsAttr(providerEl, attr)) { + for (auto targetEl : *elements) { + if (auto providers = mDependentElementsMap.Lookup(targetEl)) { + providers.Data().RemoveElementsBy( + [attr, providerEl](const auto& provider) { + return provider->mRelAttr == attr && + provider->mContent == providerEl; + }); + if (providers.Data().IsEmpty()) { + providers.Remove(); + } } } } @@ -3177,8 +3180,7 @@ void DocAccessible::MaybeHandleChangeToHiddenNameOrDescription( if (!id) { continue; } - auto* providers = - GetRelProviders(content->AsElement(), nsDependentAtomString(id)); + auto* providers = GetRelProviders(content->AsElement(), id); if (!providers) { continue; } diff --git a/accessible/generic/DocAccessible.h b/accessible/generic/DocAccessible.h @@ -329,7 +329,7 @@ class DocAccessible : public HyperTextAccessible, /** * Return true if the given ID is referred by relation attribute. */ - bool IsDependentID(dom::Element* aElement, const nsAString& aID) const { + bool IsDependentID(dom::Element* aElement, nsAtom* aID) const { return GetRelProviders(aElement, aID); } @@ -756,7 +756,7 @@ class DocAccessible : public HyperTextAccessible, }; typedef nsTArray<mozilla::UniquePtr<AttrRelProvider>> AttrRelProviders; - typedef nsClassHashtable<nsStringHashKey, AttrRelProviders> + typedef nsClassHashtable<nsAtomHashKey, AttrRelProviders> DependentIDsHashtable; /** @@ -764,11 +764,10 @@ class DocAccessible : public HyperTextAccessible, * a DOM document if the element is in uncomposed document or associated * with shadow DOM the element is in. */ - AttrRelProviders* GetRelProviders(dom::Element* aElement, - const nsAString& aID) const; + AttrRelProviders* GetRelProviders(dom::Element* aElement, nsAtom* aID) const; AttrRelProviders* GetOrCreateRelProviders(dom::Element* aElement, - const nsAString& aID); - void RemoveRelProvidersIfEmpty(dom::Element* aElement, const nsAString& aID); + nsAtom* aID); + void RemoveRelProvidersIfEmpty(dom::Element* aElement, nsAtom* aID); /** * A map used to look up the target node for an implicit reverse relation diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp @@ -2185,20 +2185,23 @@ Element* Element::GetExplicitlySetAttrElement(nsAtom* aAttr) const { return nullptr; } -void Element::GetExplicitlySetAttrElements( - nsAtom* aAttr, nsTArray<Element*>& aElements) const { +Maybe<nsTArray<RefPtr<dom::Element>>> Element::GetExplicitlySetAttrElements( + nsAtom* aAttr) const { if (const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) { if (auto attrElementsMaybeEntry = slots->mAttrElementsMap.Lookup(aAttr)) { auto& [attrElements, cachedAttrElements] = attrElementsMaybeEntry.Data(); if (attrElements) { + nsTArray<RefPtr<dom::Element>> elements; for (const nsWeakPtr& weakEl : *attrElements) { if (nsCOMPtr<Element> attrEl = do_QueryReferent(weakEl)) { - aElements.AppendElement(attrEl); + elements.AppendElement(attrEl); } } + return Some(std::move(elements)); } } } + return Nothing(); } void Element::GetElementsWithGrid(nsTArray<RefPtr<Element>>& aElements) { diff --git a/dom/base/Element.h b/dom/base/Element.h @@ -1406,8 +1406,8 @@ class Element : public FragmentOrElement { * shadow-including ancestors. It also does not attempt to retrieve elements * using the ids set in the content attribute. */ - void GetExplicitlySetAttrElements(nsAtom* aAttr, - nsTArray<Element*>& aElements) const; + Maybe<nsTArray<RefPtr<dom::Element>>> GetExplicitlySetAttrElements( + nsAtom* aAttr) const; PseudoStyleType GetPseudoElementType() const { nsresult rv = NS_OK; diff --git a/dom/html/ElementInternals.cpp b/dom/html/ElementInternals.cpp @@ -618,9 +618,9 @@ void ElementInternals::GetAttrElements( for (const nsWeakPtr& weakEl : attrElements) { // For each attrElement in reflectedTarget's explicitly set attr-elements: - if (nsCOMPtr<Element> attrEl = do_QueryReferent(weakEl)) { + if (RefPtr<Element> attrEl = do_QueryReferent(weakEl)) { // Append attrElement to elements. - elements.AppendElement(attrEl); + elements.AppendElement(std::move(attrEl)); } } @@ -654,22 +654,22 @@ void ElementInternals::GetAttrElements( cachedAttrElements = std::move(elements); } -bool ElementInternals::GetAttrElements(nsAtom* aAttr, - nsTArray<Element*>& aElements) { - aElements.Clear(); +Maybe<nsTArray<RefPtr<Element>>> ElementInternals::GetAttrElements( + nsAtom* aAttr) { auto attrElementsMaybeEntry = mAttrElementsMap.Lookup(aAttr); if (!attrElementsMaybeEntry) { - return false; + return Nothing(); } + nsTArray<RefPtr<Element>> elements; auto& [attrElements, cachedAttrElements] = attrElementsMaybeEntry.Data(); for (const nsWeakPtr& weakEl : attrElements) { - if (nsCOMPtr<Element> attrEl = do_QueryReferent(weakEl)) { - aElements.AppendElement(attrEl); + if (RefPtr<Element> attrEl = do_QueryReferent(weakEl)) { + elements.AppendElement(std::move(attrEl)); } } - return true; + return Some(std::move(elements)); } } // namespace mozilla::dom diff --git a/dom/html/ElementInternals.h b/dom/html/ElementInternals.h @@ -193,7 +193,7 @@ class ElementInternals final : public nsIFormControl, nsresult SetAttr(nsAtom* aName, const nsAString& aValue); - bool GetAttrElements(nsAtom* aAttr, nsTArray<Element*>& aElements); + Maybe<nsTArray<RefPtr<Element>>> GetAttrElements(nsAtom* aAttr); const AttrArray& GetAttrs() const { return mAttrs; }