From dfc0c9e301c2f5d75a72d3e4165d1bfb2da27ebc Mon Sep 17 00:00:00 2001 From: Alexandru Marc Date: Thu, 21 Nov 2024 10:50:49 +0200 Subject: [PATCH] Backed out 4 changesets (bug 1769586) for causing wpt failures @ property-reflection.html. CLOSED TREE Backed out changeset dc6aa76ec6c5 (bug 1769586) Backed out changeset d9ff02e6c435 (bug 1769586) Backed out changeset 446faf4cccab (bug 1769586) Backed out changeset 49f68df69db0 (bug 1769586) --- accessible/base/ARIAMap.cpp | 33 +-- accessible/base/ARIAMap.h | 25 -- accessible/base/AccIterator.cpp | 37 +-- accessible/base/AccIterator.h | 27 +- accessible/base/CachedTableAccessible.cpp | 2 +- accessible/base/nsAccUtils.cpp | 16 -- accessible/base/nsAccUtils.h | 2 - accessible/base/nsTextEquivUtils.cpp | 3 +- accessible/generic/DocAccessible.cpp | 68 +---- accessible/generic/ImageAccessible.cpp | 3 +- accessible/generic/LocalAccessible.cpp | 54 ++-- accessible/html/HTMLElementAccessibles.cpp | 3 +- .../e10s/browser_caching_relations_002.js | 244 ------------------ .../e10s/browser_treeupdate_ariaowns.js | 105 +------- accessible/tests/browser/e10s/head.js | 87 +------ dom/base/Element.cpp | 226 ++-------------- dom/base/Element.h | 39 --- dom/base/FragmentOrElement.cpp | 12 +- dom/base/FragmentOrElement.h | 15 +- dom/html/ElementInternals.cpp | 145 +---------- dom/html/ElementInternals.h | 37 +-- dom/webidl/ARIAMixin.webidl | 28 -- .../ElementInternals-accessibility.html.ini | 21 ++ ...internals-aria-element-reflection.html.ini | 3 +- ...a-element-reflection-disconnected.html.ini | 2 + ...ria-element-reflection-labelledby.html.ini | 12 + .../html/dom/aria-element-reflection.html.ini | 32 +++ .../meta/wai-aria/idlharness.window.js.ini | 41 +++ 28 files changed, 221 insertions(+), 1101 deletions(-) create mode 100644 testing/web-platform/meta/html/dom/aria-element-reflection-labelledby.html.ini diff --git a/accessible/base/ARIAMap.cpp b/accessible/base/ARIAMap.cpp index 20fccdcea811..fd5a30d24189 100644 --- a/accessible/base/ARIAMap.cpp +++ b/accessible/base/ARIAMap.cpp @@ -1451,33 +1451,33 @@ static const AttrCharacteristics gWAIUnivAttrMap[] = { {nsGkAtoms::aria_checked, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, /* exposes checkable obj attr */ {nsGkAtoms::aria_colcount, ATTR_VALINT }, {nsGkAtoms::aria_colindex, ATTR_VALINT }, - {nsGkAtoms::aria_controls, ATTR_BYPASSOBJ | ATTR_GLOBAL | ATTR_REFLECT_ELEMENTS }, + {nsGkAtoms::aria_controls, ATTR_BYPASSOBJ | ATTR_GLOBAL }, {nsGkAtoms::aria_current, ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL }, - {nsGkAtoms::aria_describedby, ATTR_BYPASSOBJ | ATTR_GLOBAL | ATTR_REFLECT_ELEMENTS }, + {nsGkAtoms::aria_describedby, ATTR_BYPASSOBJ | ATTR_GLOBAL }, // XXX Ideally, aria-description shouldn't expose a description object // attribute (i.e. it should have ATTR_BYPASSOBJ). However, until the // description-from attribute is implemented (bug 1726087), clients such as // NVDA depend on the description object attribute to work out whether the // accDescription originated from aria-description. {nsGkAtoms::aria_description, ATTR_GLOBAL }, - {nsGkAtoms::aria_details, ATTR_BYPASSOBJ | ATTR_GLOBAL | ATTR_REFLECT_ELEMENTS }, + {nsGkAtoms::aria_details, ATTR_BYPASSOBJ | ATTR_GLOBAL }, {nsGkAtoms::aria_disabled, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, {nsGkAtoms::aria_dropeffect, ATTR_VALTOKEN | ATTR_GLOBAL }, - {nsGkAtoms::aria_errormessage, ATTR_BYPASSOBJ | ATTR_GLOBAL | ATTR_REFLECT_ELEMENTS }, + {nsGkAtoms::aria_errormessage, ATTR_BYPASSOBJ | ATTR_GLOBAL }, {nsGkAtoms::aria_expanded, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, - {nsGkAtoms::aria_flowto, ATTR_BYPASSOBJ | ATTR_GLOBAL | ATTR_REFLECT_ELEMENTS }, + {nsGkAtoms::aria_flowto, ATTR_BYPASSOBJ | ATTR_GLOBAL }, {nsGkAtoms::aria_grabbed, ATTR_VALTOKEN | ATTR_GLOBAL }, {nsGkAtoms::aria_haspopup, ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL }, {nsGkAtoms::aria_hidden, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, /* handled special way */ {nsGkAtoms::aria_invalid, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, {nsGkAtoms::aria_label, ATTR_BYPASSOBJ | ATTR_GLOBAL }, - {nsGkAtoms::aria_labelledby, ATTR_BYPASSOBJ | ATTR_GLOBAL | ATTR_REFLECT_ELEMENTS }, + {nsGkAtoms::aria_labelledby, ATTR_BYPASSOBJ | ATTR_GLOBAL }, {nsGkAtoms::aria_level, ATTR_BYPASSOBJ }, /* handled via groupPosition */ {nsGkAtoms::aria_live, ATTR_VALTOKEN | ATTR_GLOBAL }, {nsGkAtoms::aria_modal, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, {nsGkAtoms::aria_multiline, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, {nsGkAtoms::aria_multiselectable, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, - {nsGkAtoms::aria_owns, ATTR_BYPASSOBJ | ATTR_GLOBAL | ATTR_REFLECT_ELEMENTS }, + {nsGkAtoms::aria_owns, ATTR_BYPASSOBJ | ATTR_GLOBAL }, {nsGkAtoms::aria_orientation, ATTR_VALTOKEN }, {nsGkAtoms::aria_posinset, ATTR_BYPASSOBJ }, /* handled via groupPosition */ {nsGkAtoms::aria_pressed, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, @@ -1737,22 +1737,3 @@ bool AttrIterator::ExposeAttr(AccAttributes* aTargetAttrs) const { } return false; } - -//////////////////////////////////////////////////////////////////////////////// -// AttrWithCharacteristicsIterator class -bool AttrWithCharacteristicsIterator::Next() { - for (mIdx++; mIdx < static_cast(std::size(gWAIUnivAttrMap)); - mIdx++) { - if (gWAIUnivAttrMap[mIdx].characteristics & mCharacteristics) { - return true; - } - } - - return false; -} - -nsStaticAtom* AttrWithCharacteristicsIterator::AttrName() const { - return mIdx >= 0 - ? const_cast(gWAIUnivAttrMap[mIdx].attributeName) - : nullptr; -} diff --git a/accessible/base/ARIAMap.h b/accessible/base/ARIAMap.h index 984072e26779..2fa3ac80d4a7 100644 --- a/accessible/base/ARIAMap.h +++ b/accessible/base/ARIAMap.h @@ -124,11 +124,6 @@ const uint8_t ATTR_GLOBAL = 0x1 << 3; */ const uint8_t ATTR_VALINT = 0x1 << 4; -/** - * Indicates that the attribute can have reflected elements. - */ -const uint8_t ATTR_REFLECT_ELEMENTS = 0x1 << 5; - //////////////////////////////////////////////////////////////////////////////// // State map entry @@ -351,26 +346,6 @@ class AttrIterator { uint8_t mAttrCharacteristics; }; -class AttrWithCharacteristicsIterator { - public: - explicit AttrWithCharacteristicsIterator(uint8_t aCharacteristics) - : mIdx(-1), mCharacteristics(aCharacteristics) {} - - bool Next(); - - nsStaticAtom* AttrName() const; - - private: - AttrWithCharacteristicsIterator() = delete; - AttrWithCharacteristicsIterator(const AttrWithCharacteristicsIterator&) = - delete; - AttrWithCharacteristicsIterator& operator=( - const AttrWithCharacteristicsIterator&) = delete; - - int32_t mIdx; - uint8_t mCharacteristics; -}; - } // namespace aria } // namespace a11y } // namespace mozilla diff --git a/accessible/base/AccIterator.cpp b/accessible/base/AccIterator.cpp index 8d3ce431509f..d28d5fcbe962 100644 --- a/accessible/base/AccIterator.cpp +++ b/accessible/base/AccIterator.cpp @@ -5,15 +5,12 @@ #include "AccIterator.h" #include "AccGroupInfo.h" -#include "ARIAMap.h" #include "DocAccessible-inl.h" #include "LocalAccessible-inl.h" -#include "nsAccUtils.h" #include "XULTreeAccessible.h" #include "mozilla/a11y/DocAccessibleParent.h" #include "mozilla/dom/DocumentOrShadowRoot.h" -#include "mozilla/dom/Element.h" #include "mozilla/dom/HTMLLabelElement.h" using namespace mozilla; @@ -243,24 +240,18 @@ LocalAccessible* XULDescriptionIterator::Next() { } //////////////////////////////////////////////////////////////////////////////// -// AssociatedElementsIterator +// IDRefsIterator //////////////////////////////////////////////////////////////////////////////// -AssociatedElementsIterator::AssociatedElementsIterator(DocAccessible* aDoc, - nsIContent* aContent, - nsAtom* aIDRefsAttr) - : mContent(aContent), mDoc(aDoc), mCurrIdx(0), mElemIdx(0) { +IDRefsIterator::IDRefsIterator(DocAccessible* aDoc, nsIContent* aContent, + nsAtom* aIDRefsAttr) + : mContent(aContent), mDoc(aDoc), mCurrIdx(0) { if (mContent->IsElement()) { mContent->AsElement()->GetAttr(aIDRefsAttr, mIDs); - if (mIDs.IsEmpty() && - (aria::AttrCharacteristicsFor(aIDRefsAttr) & ATTR_REFLECT_ELEMENTS)) { - nsAccUtils::GetARIAElementsAttr(mContent->AsElement(), aIDRefsAttr, - mElements); - } } } -const nsDependentSubstring AssociatedElementsIterator::NextID() { +const nsDependentSubstring IDRefsIterator::NextID() { for (; mCurrIdx < mIDs.Length(); mCurrIdx++) { if (!NS_IsAsciiWhitespace(mIDs[mCurrIdx])) break; } @@ -275,7 +266,7 @@ const nsDependentSubstring AssociatedElementsIterator::NextID() { return Substring(mIDs, idStartIdx, mCurrIdx++ - idStartIdx); } -nsIContent* AssociatedElementsIterator::NextElem() { +nsIContent* IDRefsIterator::NextElem() { while (true) { const nsDependentSubstring id = NextID(); if (id.IsEmpty()) break; @@ -284,18 +275,11 @@ nsIContent* AssociatedElementsIterator::NextElem() { if (refContent) return refContent; } - while (nsIContent* element = mElements.SafeElementAt(mElemIdx++)) { - if (nsCoreUtils::IsDescendantOfAnyShadowIncludingAncestor(element, - mContent)) { - return element; - } - } - return nullptr; } -dom::Element* AssociatedElementsIterator::GetElem(nsIContent* aContent, - const nsAString& aID) { +dom::Element* IDRefsIterator::GetElem(nsIContent* aContent, + const nsAString& aID) { // Get elements in DOM tree by ID attribute if this is an explicit content. // In case of bound element check its anonymous subtree. if (!aContent->IsInNativeAnonymousSubtree()) { @@ -311,12 +295,11 @@ dom::Element* AssociatedElementsIterator::GetElem(nsIContent* aContent, return nullptr; } -dom::Element* AssociatedElementsIterator::GetElem( - const nsDependentSubstring& aID) { +dom::Element* IDRefsIterator::GetElem(const nsDependentSubstring& aID) { return GetElem(mContent, aID); } -LocalAccessible* AssociatedElementsIterator::Next() { +LocalAccessible* IDRefsIterator::Next() { nsIContent* nextEl = nullptr; while ((nextEl = NextElem())) { LocalAccessible* acc = mDoc->GetAccessible(nextEl); diff --git a/accessible/base/AccIterator.h b/accessible/base/AccIterator.h index 8c627c646fcb..61b126c81294 100644 --- a/accessible/base/AccIterator.h +++ b/accessible/base/AccIterator.h @@ -16,10 +16,6 @@ class nsITreeView; namespace mozilla { -namespace dom { -class Element; -} - namespace a11y { class DocAccessibleParent; @@ -206,16 +202,15 @@ class XULDescriptionIterator : public AccIterable { }; /** - * Used to iterate through elements referenced through explicitly set - * attr-elements or IDs listed in a content attribute. Note, any method used to - * iterate through IDs, elements, or accessibles moves iterator to next - * position. + * Used to iterate through IDs, elements or accessibles pointed by IDRefs + * attribute. Note, any method used to iterate through IDs, elements, or + * accessibles moves iterator to next position. */ -class AssociatedElementsIterator : public AccIterable { +class IDRefsIterator : public AccIterable { public: - AssociatedElementsIterator(DocAccessible* aDoc, nsIContent* aContent, - nsAtom* aIDRefsAttr); - virtual ~AssociatedElementsIterator() {} + IDRefsIterator(DocAccessible* aDoc, nsIContent* aContent, + nsAtom* aIDRefsAttr); + virtual ~IDRefsIterator() {} /** * Return next ID. @@ -237,16 +232,14 @@ class AssociatedElementsIterator : public AccIterable { virtual LocalAccessible* Next() override; private: - AssociatedElementsIterator(); - AssociatedElementsIterator(const AssociatedElementsIterator&); - AssociatedElementsIterator operator=(const AssociatedElementsIterator&); + IDRefsIterator(); + IDRefsIterator(const IDRefsIterator&); + IDRefsIterator operator=(const IDRefsIterator&); nsString mIDs; nsIContent* mContent; DocAccessible* mDoc; nsAString::index_type mCurrIdx; - nsTArray mElements; - uint32_t mElemIdx; }; /** diff --git a/accessible/base/CachedTableAccessible.cpp b/accessible/base/CachedTableAccessible.cpp index 8d59a93053b9..905549ed3655 100644 --- a/accessible/base/CachedTableAccessible.cpp +++ b/accessible/base/CachedTableAccessible.cpp @@ -340,7 +340,7 @@ UniquePtr CachedTableCellAccessible::GetExplicitHeadersIterator() { } } } else if (LocalAccessible* localAcc = mAcc->AsLocal()) { - return MakeUnique( + return MakeUnique( localAcc->Document(), localAcc->GetContent(), nsGkAtoms::headers); } return nullptr; diff --git a/accessible/base/nsAccUtils.cpp b/accessible/base/nsAccUtils.cpp index 7e0b51248226..de2e97a4693a 100644 --- a/accessible/base/nsAccUtils.cpp +++ b/accessible/base/nsAccUtils.cpp @@ -568,22 +568,6 @@ const nsAttrValue* nsAccUtils::GetARIAAttr(dom::Element* aElement, return defaults->GetAttr(aName, kNameSpaceID_None); } -bool nsAccUtils::GetARIAElementsAttr(dom::Element* aElement, nsAtom* aName, - nsTArray& aElements) { - if (aElement->HasAttr(aName)) { - aElement->GetExplicitlySetAttrElements(aName, aElements); - return true; - } - - if (auto* element = nsGenericHTMLElement::FromNode(aElement)) { - if (auto* internals = element->GetInternals()) { - return internals->GetAttrElements(aName, aElements); - } - } - - return false; -} - bool nsAccUtils::ARIAAttrValueIs(dom::Element* aElement, const nsAtom* aName, const nsAString& aValue, nsCaseTreatment aCaseSensitive) { diff --git a/accessible/base/nsAccUtils.h b/accessible/base/nsAccUtils.h index ab615604acfe..07e32f1cdbaf 100644 --- a/accessible/base/nsAccUtils.h +++ b/accessible/base/nsAccUtils.h @@ -288,8 +288,6 @@ class nsAccUtils { nsAString& aResult); static const nsAttrValue* GetARIAAttr(dom::Element* aElement, const nsAtom* aName); - static bool GetARIAElementsAttr(dom::Element* aElement, nsAtom* aName, - nsTArray& aElements); static bool ARIAAttrValueIs(dom::Element* aElement, const nsAtom* aName, const nsAString& aValue, nsCaseTreatment aCaseSensitive); diff --git a/accessible/base/nsTextEquivUtils.cpp b/accessible/base/nsTextEquivUtils.cpp index c350d37f12e2..34511c899d63 100644 --- a/accessible/base/nsTextEquivUtils.cpp +++ b/accessible/base/nsTextEquivUtils.cpp @@ -99,8 +99,7 @@ nsresult nsTextEquivUtils::GetTextEquivFromIDRefs( if (!content) return NS_OK; nsIContent* refContent = nullptr; - AssociatedElementsIterator iter(aAccessible->Document(), content, - aIDRefsAttr); + IDRefsIterator iter(aAccessible->Document(), content, aIDRefsAttr); while ((refContent = iter.NextElem())) { if (!aTextEquiv.IsEmpty()) aTextEquiv += ' '; diff --git a/accessible/generic/DocAccessible.cpp b/accessible/generic/DocAccessible.cpp index 83f1051287b6..814129dcc910 100644 --- a/accessible/generic/DocAccessible.cpp +++ b/accessible/generic/DocAccessible.cpp @@ -7,7 +7,6 @@ #include "LocalAccessible-inl.h" #include "AccIterator.h" #include "AccAttributes.h" -#include "ARIAMap.h" #include "CachedTableAccessible.h" #include "DocAccessible-inl.h" #include "EventTree.h" @@ -804,10 +803,11 @@ void DocAccessible::AttributeWillChange(dom::Element* aElement, // Update dependent IDs cache. Take care of elements that are accessible // because dependent IDs cache doesn't contain IDs from non accessible - // elements. We do this for attribute additions as well because there might - // be an ElementInternals default value. - RemoveDependentIDsFor(accessible, aAttribute); - RemoveDependentElementsFor(accessible, aAttribute); + // elements. + if (aModType != dom::MutationEvent_Binding::ADDITION) { + RemoveDependentIDsFor(accessible, aAttribute); + RemoveDependentElementsFor(accessible, aAttribute); + } if (aAttribute == nsGkAtoms::id) { if (accessible->IsActiveDescendantId()) { @@ -1247,7 +1247,7 @@ void DocAccessible::BindToDocument(LocalAccessible* aAccessible, nsIContent* content = aAccessible->GetContent(); if (content->IsElement() && - nsAccUtils::HasARIAAttr(content->AsElement(), nsGkAtoms::aria_owns)) { + content->AsElement()->HasAttr(nsGkAtoms::aria_owns)) { mNotificationController->ScheduleRelocation(aAccessible); } } @@ -1808,7 +1808,7 @@ void DocAccessible::AddDependentIDsFor(LocalAccessible* aRelProvider, } } - AssociatedElementsIterator iter(this, relProviderEl, relAttr); + IDRefsIterator iter(this, relProviderEl, relAttr); while (true) { const nsDependentSubstring id = iter.NextID(); if (id.IsEmpty()) break; @@ -1851,7 +1851,7 @@ void DocAccessible::RemoveDependentIDsFor(LocalAccessible* aRelProvider, nsStaticAtom* relAttr = kRelationAttrs[idx]; if (aRelAttr && aRelAttr != kRelationAttrs[idx]) continue; - AssociatedElementsIterator iter(this, relProviderElm, relAttr); + IDRefsIterator iter(this, relProviderElm, relAttr); while (true) { const nsDependentSubstring id = iter.NextID(); if (id.IsEmpty()) break; @@ -1897,28 +1897,6 @@ void DocAccessible::AddDependentElementsFor(LocalAccessible* aRelProvider, break; } } - - aria::AttrWithCharacteristicsIterator multipleElementsRelationIter( - ATTR_REFLECT_ELEMENTS); - while (multipleElementsRelationIter.Next()) { - nsStaticAtom* attr = multipleElementsRelationIter.AttrName(); - if (aRelAttr && aRelAttr != attr) { - continue; - } - nsTArray 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 the relation attribute was given, we've already handled it. We don't - // have anything else to check. - if (aRelAttr) { - break; - } - } } void DocAccessible::RemoveDependentElementsFor(LocalAccessible* aRelProvider, @@ -1949,34 +1927,6 @@ void DocAccessible::RemoveDependentElementsFor(LocalAccessible* aRelProvider, break; } } - - aria::AttrWithCharacteristicsIterator multipleElementsRelationIter( - ATTR_REFLECT_ELEMENTS); - while (multipleElementsRelationIter.Next()) { - nsStaticAtom* attr = multipleElementsRelationIter.AttrName(); - if (aRelAttr && aRelAttr != attr) { - continue; - } - nsTArray 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 the relation attribute was given, we've already handled it. We don't - // have anything else to check. - if (aRelAttr) { - break; - } - } } bool DocAccessible::UpdateAccessibleOnAttrChange(dom::Element* aElement, @@ -2465,7 +2415,7 @@ void DocAccessible::DoARIAOwnsRelocation(LocalAccessible* aOwner) { nsTArray>* owned = mARIAOwnsHash.GetOrInsertNew(aOwner); - AssociatedElementsIterator iter(this, aOwner->Elm(), nsGkAtoms::aria_owns); + IDRefsIterator iter(this, aOwner->Elm(), nsGkAtoms::aria_owns); uint32_t idx = 0; while (nsIContent* childEl = iter.NextElem()) { LocalAccessible* child = GetAccessible(childEl); diff --git a/accessible/generic/ImageAccessible.cpp b/accessible/generic/ImageAccessible.cpp index bcbc5225e6de..ecfdac529bf4 100644 --- a/accessible/generic/ImageAccessible.cpp +++ b/accessible/generic/ImageAccessible.cpp @@ -196,8 +196,7 @@ already_AddRefed ImageAccessible::GetLongDescURI() const { DocAccessible* document = Document(); if (document) { - AssociatedElementsIterator iter(document, mContent, - nsGkAtoms::aria_describedby); + IDRefsIterator iter(document, mContent, nsGkAtoms::aria_describedby); while (nsIContent* target = iter.NextElem()) { if ((target->IsHTMLElement(nsGkAtoms::a) || target->IsHTMLElement(nsGkAtoms::area)) && diff --git a/accessible/generic/LocalAccessible.cpp b/accessible/generic/LocalAccessible.cpp index 44fa7a2197e9..6f3659715d7a 100644 --- a/accessible/generic/LocalAccessible.cpp +++ b/accessible/generic/LocalAccessible.cpp @@ -1417,7 +1417,7 @@ void LocalAccessible::DOMAttributeChanged(int32_t aNameSpaceID, if (aAttribute == nsGkAtoms::aria_label) { // A valid aria-labelledby would take precedence so an aria-label change // won't change the name. - AssociatedElementsIterator iter(mDoc, elm, nsGkAtoms::aria_labelledby); + IDRefsIterator iter(mDoc, elm, nsGkAtoms::aria_labelledby); if (!iter.NextElem()) { mDoc->FireDelayedEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this); } @@ -1427,7 +1427,7 @@ void LocalAccessible::DOMAttributeChanged(int32_t aNameSpaceID, if (aAttribute == nsGkAtoms::aria_description) { // A valid aria-describedby would take precedence so an aria-description // change won't change the description. - AssociatedElementsIterator iter(mDoc, elm, nsGkAtoms::aria_describedby); + IDRefsIterator iter(mDoc, elm, nsGkAtoms::aria_describedby); if (!iter.NextElem()) { mDoc->FireDelayedEvent(nsIAccessibleEvent::EVENT_DESCRIPTION_CHANGE, this); @@ -1443,7 +1443,7 @@ void LocalAccessible::DOMAttributeChanged(int32_t aNameSpaceID, // The subtrees of the new aria-describedby targets might be used to // compute the description for this. Therefore, we need to set // the eHasDescriptionDependent flag on all Accessibles in these subtrees. - AssociatedElementsIterator iter(mDoc, elm, nsGkAtoms::aria_describedby); + IDRefsIterator iter(mDoc, elm, nsGkAtoms::aria_describedby); while (LocalAccessible* target = iter.Next()) { target->ModifySubtreeContextFlags(eHasDescriptionDependent, true); } @@ -1462,7 +1462,7 @@ void LocalAccessible::DOMAttributeChanged(int32_t aNameSpaceID, // The subtrees of the new aria-labelledby targets might be used to // compute the name for this. Therefore, we need to set // the eHasNameDependent flag on all Accessibles in these subtrees. - AssociatedElementsIterator iter(mDoc, elm, nsGkAtoms::aria_labelledby); + IDRefsIterator iter(mDoc, elm, nsGkAtoms::aria_labelledby); while (LocalAccessible* target = iter.Next()) { target->ModifySubtreeContextFlags(eHasNameDependent, true); } @@ -2168,8 +2168,8 @@ Relation LocalAccessible::RelationByType(RelationType aType) const { // defined on. switch (aType) { case RelationType::LABELLED_BY: { - Relation rel(new AssociatedElementsIterator(mDoc, mContent, - nsGkAtoms::aria_labelledby)); + Relation rel( + new IDRefsIterator(mDoc, mContent, nsGkAtoms::aria_labelledby)); if (mContent->IsHTMLElement()) { rel.AppendIter(new HTMLLabelIterator(Document(), this)); } @@ -2182,16 +2182,15 @@ Relation LocalAccessible::RelationByType(RelationType aType) const { Relation rel(new RelatedAccIterator(Document(), mContent, nsGkAtoms::aria_labelledby)); if (mContent->IsXULElement(nsGkAtoms::label)) { - rel.AppendIter( - new AssociatedElementsIterator(mDoc, mContent, nsGkAtoms::control)); + rel.AppendIter(new IDRefsIterator(mDoc, mContent, nsGkAtoms::control)); } return rel; } case RelationType::DESCRIBED_BY: { - Relation rel(new AssociatedElementsIterator(mDoc, mContent, - nsGkAtoms::aria_describedby)); + Relation rel( + new IDRefsIterator(mDoc, mContent, nsGkAtoms::aria_describedby)); if (mContent->IsXULElement()) { rel.AppendIter(new XULDescriptionIterator(Document(), mContent)); } @@ -2207,8 +2206,7 @@ Relation LocalAccessible::RelationByType(RelationType aType) const { // which only affects accessibility, by allowing the description to be // tied to a control. if (mContent->IsXULElement(nsGkAtoms::description)) { - rel.AppendIter( - new AssociatedElementsIterator(mDoc, mContent, nsGkAtoms::control)); + rel.AppendIter(new IDRefsIterator(mDoc, mContent, nsGkAtoms::control)); } return rel; @@ -2287,15 +2285,15 @@ Relation LocalAccessible::RelationByType(RelationType aType) const { nsGkAtoms::aria_controls)); case RelationType::CONTROLLER_FOR: { - Relation rel(new AssociatedElementsIterator(mDoc, mContent, - nsGkAtoms::aria_controls)); + Relation rel( + new IDRefsIterator(mDoc, mContent, nsGkAtoms::aria_controls)); rel.AppendIter(new HTMLOutputIterator(Document(), mContent)); return rel; } case RelationType::FLOWS_TO: - return Relation(new AssociatedElementsIterator(mDoc, mContent, - nsGkAtoms::aria_flowto)); + return Relation( + new IDRefsIterator(mDoc, mContent, nsGkAtoms::aria_flowto)); case RelationType::FLOWS_FROM: return Relation( @@ -2445,10 +2443,9 @@ Relation LocalAccessible::RelationByType(RelationType aType) const { case RelationType::DETAILS: { if (mContent->IsElement() && - nsAccUtils::HasARIAAttr(mContent->AsElement(), - nsGkAtoms::aria_details)) { - return Relation(new AssociatedElementsIterator( - mDoc, mContent, nsGkAtoms::aria_details)); + mContent->AsElement()->HasAttr(nsGkAtoms::aria_details)) { + return Relation( + new IDRefsIterator(mDoc, mContent, nsGkAtoms::aria_details)); } if (LocalAccessible* target = GetPopoverTargetDetailsRelation()) { return Relation(target); @@ -2475,8 +2472,8 @@ Relation LocalAccessible::RelationByType(RelationType aType) const { } case RelationType::ERRORMSG: - return Relation(new AssociatedElementsIterator( - mDoc, mContent, nsGkAtoms::aria_errormessage)); + return Relation( + new IDRefsIterator(mDoc, mContent, nsGkAtoms::aria_errormessage)); case RelationType::ERRORMSG_FOR: return Relation( @@ -3981,7 +3978,7 @@ already_AddRefed LocalAccessible::BundleFieldsForCache( } if (mContent->AsElement()->HasAttr(nsGkAtoms::headers)) { nsTArray headers; - AssociatedElementsIterator iter(mDoc, mContent, nsGkAtoms::headers); + IDRefsIterator iter(mDoc, mContent, nsGkAtoms::headers); while (LocalAccessible* cell = iter.Next()) { if (cell->IsTableCell()) { headers.AppendElement(cell->ID()); @@ -4052,12 +4049,11 @@ already_AddRefed LocalAccessible::BundleFieldsForCache( // relation, so using RelationByType here is fine. rel = RelationByType(RelationType::DETAILS); } else { - // We use an AssociatedElementsIterator here instead of calling - // RelationByType directly because we only want to cache explicit - // relations. Implicit relations (e.g. LABEL_FOR exposed on the target - // of aria-labelledby) will be computed and stored separately in the - // parent process. - rel.AppendIter(new AssociatedElementsIterator(mDoc, mContent, relAtom)); + // We use an IDRefsIterator here instead of calling RelationByType + // directly because we only want to cache explicit relations. Implicit + // relations (e.g. LABEL_FOR exposed on the target of aria-labelledby) + // will be computed and stored separately in the parent process. + rel.AppendIter(new IDRefsIterator(mDoc, mContent, relAtom)); } while (LocalAccessible* acc = rel.LocalNext()) { diff --git a/accessible/html/HTMLElementAccessibles.cpp b/accessible/html/HTMLElementAccessibles.cpp index f1adbde5f1a3..135f9973588a 100644 --- a/accessible/html/HTMLElementAccessibles.cpp +++ b/accessible/html/HTMLElementAccessibles.cpp @@ -88,8 +88,7 @@ void HTMLLabelAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) { Relation HTMLOutputAccessible::RelationByType(RelationType aType) const { Relation rel = AccessibleWrap::RelationByType(aType); if (aType == RelationType::CONTROLLED_BY) { - rel.AppendIter( - new AssociatedElementsIterator(mDoc, mContent, nsGkAtoms::_for)); + rel.AppendIter(new IDRefsIterator(mDoc, mContent, nsGkAtoms::_for)); } return rel; diff --git a/accessible/tests/browser/e10s/browser_caching_relations_002.js b/accessible/tests/browser/e10s/browser_caching_relations_002.js index 34661bb3e6c1..61d92ba4acf9 100644 --- a/accessible/tests/browser/e10s/browser_caching_relations_002.js +++ b/accessible/tests/browser/e10s/browser_caching_relations_002.js @@ -467,247 +467,3 @@ between }, { chrome: true, topLevel: true } ); - -/** - * Test relation defaults via element internals - */ -addAccessibleTask( - ` -
label
- -
label2
- -`, - async function (browser, accDoc) { - let host = findAccessibleChildByID(accDoc, "host"); - let dependant1 = findAccessibleChildByID(accDoc, "dependant1"); - let dependant2 = findAccessibleChildByID(accDoc, "dependant2"); - - function invokeSetInternals(reflectionAttrName, targetIds) { - if (targetIds) { - Logger.log( - `Setting internals reflected ${reflectionAttrName} attribute to ${targetIds} for host` - ); - } else { - Logger.log( - `Removing internals reflected ${reflectionAttrName} attribute from node with host` - ); - } - - return invokeContentTask( - browser, - [reflectionAttrName, targetIds], - (contentAttr, contentTargetIds) => { - let internals = content.document.getElementById("host").internals; - if (contentTargetIds) { - internals[contentAttr] = contentTargetIds.map(targetId => - content.document.getElementById(targetId) - ); - } else { - internals[contentAttr] = null; - } - } - ); - } - - async function testInternalsRelation( - attrName, - reflectionAttrName, - hostRelation, - dependantRelation - ) { - info(`setting default ${reflectionAttrName}`); - await invokeSetInternals(reflectionAttrName, ["dependant1"]); - await testCachedRelation(host, hostRelation, [dependant1]); - await testCachedRelation(dependant1, dependantRelation, [host]); - await testCachedRelation(dependant2, dependantRelation, null); - - info(`setting override ${attrName}`); - await invokeSetAttribute(browser, "host", attrName, "dependant2"); - await testCachedRelation(host, hostRelation, [dependant2]); - await testCachedRelation(dependant2, dependantRelation, [host]); - await testCachedRelation(dependant1, dependantRelation, null); - - info(`unsetting default ${reflectionAttrName} and ${attrName} override`); - await invokeSetInternals(reflectionAttrName, null); - await invokeSetAttribute(browser, "host", attrName, null); - await testCachedRelation(host, hostRelation, null); - await testCachedRelation(dependant2, dependantRelation, null); - await testCachedRelation(dependant1, dependantRelation, null); - } - - await testInternalsRelation( - "aria-labelledby", - "ariaLabelledByElements", - RELATION_LABELLED_BY, - RELATION_LABEL_FOR - ); - await testInternalsRelation( - "aria-describedby", - "ariaDescribedByElements", - RELATION_DESCRIBED_BY, - RELATION_DESCRIPTION_FOR - ); - await testInternalsRelation( - "aria-controls", - "ariaControlsElements", - RELATION_CONTROLLER_FOR, - RELATION_CONTROLLED_BY - ); - await testInternalsRelation( - "aria-flowto", - "ariaFlowToElements", - RELATION_FLOWS_TO, - RELATION_FLOWS_FROM - ); - await testInternalsRelation( - "aria-details", - "ariaDetailsElements", - RELATION_DETAILS, - RELATION_DETAILS_FOR - ); - await testInternalsRelation( - "aria-errormessage", - "ariaErrorMessageElements", - RELATION_ERRORMSG, - RELATION_ERRORMSG_FOR - ); - } -); - -/** - * Moving explicitly set elements across shadow DOM boundaries. - */ -addAccessibleTask( - ` -
-
Delicious
-
Nutritious
-
- -
- -`, - async function (browser, accDoc) { - const waitAndReturnRecreated = acc => { - const id = getAccessibleDOMNodeID(acc); - return waitForEvents([ - [EVENT_HIDE, acc], - [EVENT_SHOW, id], - ]).then(evts => evts[1].accessible); - }; - - let describedAcc = findAccessibleChildByID(accDoc, "describedElement"); - let accDescription1 = findAccessibleChildByID(accDoc, "buttonDescription1"); - let accDescription2 = findAccessibleChildByID(accDoc, "buttonDescription2"); - - // All elements were in the same scope, so relations are intact. - await testCachedRelation(describedAcc, RELATION_DESCRIBED_BY, [ - accDescription1, - accDescription2, - ]); - await testCachedRelation(accDescription1, RELATION_DESCRIPTION_FOR, [ - describedAcc, - ]); - await testCachedRelation(accDescription2, RELATION_DESCRIPTION_FOR, [ - describedAcc, - ]); - - let onRecreated = waitAndReturnRecreated(describedAcc); - await invokeContentTask(browser, [], () => { - const outerShadowRoot = - content.document.getElementById("outerShadowHost").shadowRoot; - const describedElement = - content.document.getElementById("describedElement"); - outerShadowRoot.appendChild(describedElement); - }); - - info("Waiting for described accessible to be recreated"); - describedAcc = await onRecreated; - // Relations should still be intact, we are referencing elements in a lighter scope. - await testCachedRelation(describedAcc, RELATION_DESCRIBED_BY, [ - accDescription1, - accDescription2, - ]); - await testCachedRelation(accDescription1, RELATION_DESCRIPTION_FOR, [ - describedAcc, - ]); - await testCachedRelation(accDescription2, RELATION_DESCRIPTION_FOR, [ - describedAcc, - ]); - - // Move the explicitly set elements into a deeper shadow DOM. - onRecreated = Promise.all([ - waitAndReturnRecreated(accDescription1), - waitAndReturnRecreated(accDescription2), - ]); - await invokeContentTask(browser, [], () => { - const buttonDescription1 = - content.document.getElementById("buttonDescription1"); - const buttonDescription2 = - content.document.getElementById("buttonDescription2"); - const innerShadowRoot = - content.document.getElementById("outerShadowHost").shadowRoot - .firstElementChild.shadowRoot; - innerShadowRoot.appendChild(buttonDescription1); - innerShadowRoot.appendChild(buttonDescription2); - }); - - [accDescription1, accDescription2] = await onRecreated; - - // Relation is severed, because relation dependants are no longer in a valid scope. - await testCachedRelation(describedAcc, RELATION_DESCRIBED_BY, []); - await testCachedRelation(accDescription1, RELATION_DESCRIPTION_FOR, []); - await testCachedRelation(accDescription2, RELATION_DESCRIPTION_FOR, []); - - // Move into the same shadow scope as the explicitly set elements. - onRecreated = waitAndReturnRecreated(describedAcc); - await invokeContentTask(browser, [], () => { - const outerShadowRoot = - content.document.getElementById("outerShadowHost").shadowRoot; - const describedElement = - outerShadowRoot.getElementById("describedElement"); - const innerShadowRoot = outerShadowRoot.firstElementChild.shadowRoot; - innerShadowRoot.appendChild(describedElement); - }); - - describedAcc = await onRecreated; - // Relation is restored, because target is now in same shadow scope. - await testCachedRelation(describedAcc, RELATION_DESCRIBED_BY, [ - accDescription1, - accDescription2, - ]); - await testCachedRelation(accDescription1, RELATION_DESCRIPTION_FOR, [ - describedAcc, - ]); - await testCachedRelation(accDescription2, RELATION_DESCRIPTION_FOR, [ - describedAcc, - ]); - } -); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js b/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js index 62ff3f5b83bf..78f52d316296 100644 --- a/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js +++ b/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js @@ -7,35 +7,7 @@ /* import-globals-from ../../mochitest/role.js */ loadScripts({ name: "role.js", dir: MOCHITESTS_DIR }); -requestLongerTimeout(2); - -function invokeSetAriaOwns( - browser, - id, - children = null, - elementReflection = false -) { - if (!elementReflection) { - return invokeSetAttribute(browser, id, "aria-owns", children); - } - - return invokeContentTask( - browser, - [id, children], - (contentId, contentChildrenIds) => { - let elm = content.document.getElementById(contentId); - if (contentChildrenIds) { - elm.ariaOwnsElements = contentChildrenIds - .split(" ") - .map(childId => content.document.getElementById(childId)); - } else { - elm.ariaOwnsElements = null; - } - } - ); -} - -async function testContainer1(browser, accDoc, elementReflection = false) { +async function testContainer1(browser, accDoc) { const id = "t1_container"; const docID = getAccessibleDOMNodeID(accDoc); const acc = findAccessibleChildByID(accDoc, id); @@ -49,12 +21,7 @@ async function testContainer1(browser, accDoc, elementReflection = false) { /* ================ Change ARIA owns ====================================== */ let onReorder = waitForEvent(EVENT_REORDER, id); - await invokeSetAriaOwns( - browser, - id, - "t1_button t1_subdiv", - elementReflection - ); + await invokeSetAttribute(browser, id, "aria-owns", "t1_button t1_subdiv"); await onReorder; // children are swapped again, button and subdiv are appended to @@ -70,7 +37,7 @@ async function testContainer1(browser, accDoc, elementReflection = false) { /* ================ Remove ARIA owns ====================================== */ onReorder = waitForEvent(EVENT_REORDER, id); - await invokeSetAriaOwns(browser, id, null, elementReflection); + await invokeSetAttribute(browser, id, "aria-owns"); await onReorder; // children follow the DOM order @@ -81,12 +48,7 @@ async function testContainer1(browser, accDoc, elementReflection = false) { /* ================ Set ARIA owns ========================================= */ onReorder = waitForEvent(EVENT_REORDER, id); - await invokeSetAriaOwns( - browser, - id, - "t1_button t1_subdiv", - elementReflection - ); + await invokeSetAttribute(browser, id, "aria-owns", "t1_button t1_subdiv"); await onReorder; // children are swapped again, button and subdiv are appended to @@ -218,7 +180,7 @@ async function removeContainer(browser, accDoc) { testAccessibleTree(acc, tree); } -async function stealAndRecacheChildren(browser, accDoc, elementReflection) { +async function stealAndRecacheChildren(browser, accDoc) { const id1 = "t3_container1"; const id2 = "t3_container2"; const acc1 = findAccessibleChildByID(accDoc, id1); @@ -226,7 +188,7 @@ async function stealAndRecacheChildren(browser, accDoc, elementReflection) { /* ================ Attempt to steal from other ARIA owns ================= */ let onReorder = waitForEvent(EVENT_REORDER, id2); - await invokeSetAriaOwns(browser, id2, "t3_child", elementReflection); + await invokeSetAttribute(browser, id2, "aria-owns", "t3_child"); await invokeContentTask(browser, [id2], id => { let div = content.document.createElement("div"); div.setAttribute("role", "radio"); @@ -266,7 +228,7 @@ async function showHiddenElement(browser, accDoc) { testAccessibleTree(acc, tree); } -async function rearrangeARIAOwns(browser, accDoc, elementReflection) { +async function rearrangeARIAOwns(browser, accDoc) { const id = "t5_container"; const acc = findAccessibleChildByID(accDoc, id); const tests = [ @@ -282,7 +244,7 @@ async function rearrangeARIAOwns(browser, accDoc, elementReflection) { for (let { val, roleList } of tests) { let onReorder = waitForEvent(EVENT_REORDER, id); - await invokeSetAriaOwns(browser, id, val, elementReflection); + await invokeSetAttribute(browser, id, "aria-owns", val); await onReorder; let tree = { SECTION: [] }; @@ -331,19 +293,6 @@ addAccessibleTask( { iframe: true, remoteIframe: true } ); -addAccessibleTask( - "e10s/doc_treeupdate_ariaowns.html", - async function (browser, accDoc) { - await testContainer1(browser, accDoc, true); - await removeContainer(browser, accDoc); - await stealAndRecacheChildren(browser, accDoc, true); - await showHiddenElement(browser, accDoc); - await rearrangeARIAOwns(browser, accDoc, true); - await removeNotARIAOwnedEl(browser, accDoc); - }, - { iframe: true, remoteIframe: true } -); - // Test owning an ancestor which isn't created yet with an iframe in the // subtree. addAccessibleTask( @@ -506,41 +455,3 @@ addAccessibleTask( }, { chrome: false, iframe: true, remoteIframe: true } ); - -/** - * Test relation defaults via element internals - */ -addAccessibleTask( - ` - -
-
-
-
-
- -
-
-
- -`, - async function (browser, accDoc) { - let listbox = findAccessibleChildByID(accDoc, "listbox"); - is(listbox.children.length, 3, "got children"); - let onReorder = waitForEvent(EVENT_REORDER, "listbox"); - invokeSetAriaOwns(browser, "listbox", "l4"); - await onReorder; - } -); diff --git a/accessible/tests/browser/e10s/head.js b/accessible/tests/browser/e10s/head.js index 2c28af23f3aa..e72af914d482 100644 --- a/accessible/tests/browser/e10s/head.js +++ b/accessible/tests/browser/e10s/head.js @@ -134,50 +134,6 @@ async function testCachedRelation(identifier, relType, relatedIdentifiers) { }, "No unexpected targets found."); } -/** - * Asynchronously set or remove content element's reflected elements attribute - * (in content process if e10s is enabled). - * @param {Object} browser current "tabbrowser" element - * @param {String} id content element id - * @param {String} attr attribute name - * @param {String?} value optional attribute value, if not present, remove - * attribute - * @return {Promise} promise indicating that attribute is set/removed - */ -function invokeSetReflectedElementsAttribute(browser, id, attr, targetIds) { - if (targetIds) { - Logger.log( - `Setting reflected ${attr} attribute to ${targetIds} for node with id: ${id}` - ); - } else { - Logger.log(`Removing reflected ${attr} attribute from node with id: ${id}`); - } - - return invokeContentTask( - browser, - [id, attr, targetIds], - (contentId, contentAttr, contentTargetIds) => { - let elm = content.document.getElementById(contentId); - if (contentTargetIds) { - elm[contentAttr] = contentTargetIds.map(targetId => - content.document.getElementById(targetId) - ); - } else { - elm[contentAttr] = null; - } - } - ); -} - -const REFLECTEDATTR_NAME_MAP = { - "aria-controls": "ariaControlsElements", - "aria-describedby": "ariaDescribedByElements", - "aria-details": "ariaDetailsElements", - "aria-errormessage": "ariaErrorMessageElements", - "aria-flowto": "ariaFlowToElements", - "aria-labelledby": "ariaLabelledByElements", -}; - async function testRelated( browser, accDoc, @@ -192,14 +148,13 @@ async function testRelated( /** * Test data has the format of: * { - * desc {String} description for better logging - * attrs {?Array} an optional list of attributes to update - * reflectedattr {?Array} an optional list of reflected attributes to update - * expected {Array} expected relation values for dependant1, dependant2 + * desc {String} description for better logging + * attrs {?Array} an optional list of attributes to update + * expected {Array} expected relation values for dependant1, dependant2 * and host respectively. * } */ - let tests = [ + const tests = [ { desc: "No attribute", expected: [null, null, null], @@ -226,45 +181,13 @@ async function testRelated( }, ]; - let reflectedAttrName = REFLECTEDATTR_NAME_MAP[attr]; - if (reflectedAttrName) { - tests = tests.concat([ - { - desc: "Set reflected attribute", - reflectedattr: [{ key: reflectedAttrName, value: ["dependant1"] }], - expected: [host, null, dependant1], - }, - { - desc: "Change reflected attribute", - reflectedattr: [{ key: reflectedAttrName, value: ["dependant2"] }], - expected: [null, host, dependant2], - }, - { - desc: "Change reflected attribute to multiple targets", - reflectedattr: [ - { key: reflectedAttrName, value: ["dependant2", "dependant1"] }, - ], - expected: [host, host, [dependant1, dependant2]], - }, - { - desc: "Remove reflected attribute", - reflectedattr: [{ key: reflectedAttrName, value: null }], - expected: [null, null, null], - }, - ]); - } - - for (let { desc, attrs, reflectedattr, expected } of tests) { + for (let { desc, attrs, expected } of tests) { info(desc); if (attrs) { for (let { key, value } of attrs) { await invokeSetAttribute(browser, "host", key, value); } - } else if (reflectedattr) { - for (let { key, value } of reflectedattr) { - await invokeSetReflectedElementsAttribute(browser, "host", key, value); - } } await testCachedRelation(dependant1, dependantRelation, expected[0]); diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index b931f910c7a7..8c80d968732f 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -1760,40 +1760,25 @@ already_AddRefed Element::GetElementsByClassName( return nsContentUtils::GetElementsByClassName(this, aClassNames); } -bool Element::HasSharedRoot(const Element* aElement) const { - nsINode* root = SubtreeRoot(); - nsINode* attrSubtreeRoot = aElement->SubtreeRoot(); - do { - if (root == attrSubtreeRoot) { - return true; - } - auto* shadow = ShadowRoot::FromNode(root); - if (!shadow || !shadow->GetHost()) { - break; - } - root = shadow->GetHost()->SubtreeRoot(); - } while (true); - return false; -} - -Element* Element::GetElementByIdInDocOrSubtree(nsAtom* aID) const { - if (auto* docOrShadowRoot = GetContainingDocumentOrShadowRoot()) { - return docOrShadowRoot->GetElementById(aID); - } - - return nsContentUtils::MatchElementId(SubtreeRoot()->AsContent(), aID); -} - Element* Element::GetAttrAssociatedElement(nsAtom* aAttr) const { if (const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) { - nsWeakPtr weakAttrEl = slots->mExplicitlySetAttrElementMap.Get(aAttr); + nsWeakPtr weakAttrEl = slots->mExplicitlySetAttrElements.Get(aAttr); if (nsCOMPtr attrEl = do_QueryReferent(weakAttrEl)) { // If reflectedTarget's explicitly set attr-element |attrEl| is // a descendant of any of element's shadow-including ancestors, then // return |atrEl|. - if (HasSharedRoot(attrEl)) { - return attrEl; - } + nsINode* root = SubtreeRoot(); + nsINode* attrSubtreeRoot = attrEl->SubtreeRoot(); + do { + if (root == attrSubtreeRoot) { + return attrEl; + } + auto* shadow = ShadowRoot::FromNode(root); + if (!shadow || !shadow->GetHost()) { + break; + } + root = shadow->GetHost()->SubtreeRoot(); + } while (true); return nullptr; } } @@ -1806,102 +1791,23 @@ Element* Element::GetAttrAssociatedElement(nsAtom* aAttr) const { MOZ_ASSERT(value->Type() == nsAttrValue::eAtom, "Attribute used for attr associated element must be parsed"); - return GetElementByIdInDocOrSubtree(value->GetAtomValue()); -} + nsAtom* valueAtom = value->GetAtomValue(); + if (auto* docOrShadowRoot = GetContainingDocumentOrShadowRoot()) { + return docOrShadowRoot->GetElementById(valueAtom); + } -void Element::GetAttrAssociatedElements( - nsAtom* aAttr, bool* aUseCachedValue, - Nullable>>& aElements) { - MOZ_ASSERT(aElements.IsNull()); - - auto& [explicitlySetAttrElements, cachedAttrElements] = - ExtendedDOMSlots()->mAttrElementsMap.LookupOrInsert(aAttr); - - // https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#attr-associated-elements - auto getAttrAssociatedElements = - [&, &explicitlySetAttrElements = - explicitlySetAttrElements]() -> Maybe>> { - nsTArray> elements; - - if (explicitlySetAttrElements) { - // 3. If reflectedTarget's explicitly set attr-elements is not null - for (const nsWeakPtr& weakEl : *explicitlySetAttrElements) { - // For each attrElement in reflectedTarget's explicitly set - // attr-elements: - if (nsCOMPtr attrEl = do_QueryReferent(weakEl)) { - // If attrElement is not a descendant of any of element's - // shadow-including ancestors, then continue. - if (!HasSharedRoot(attrEl)) { - continue; - } - // Append attrElement to elements. - elements.AppendElement(attrEl); - } - } - } else { - // 4. Otherwise - // 1. Let contentAttributeValue be the result of running - // reflectedTarget's get the content attribute. - const nsAttrValue* value = GetParsedAttr(aAttr); - // 2. If contentAttributeValue is null, then return null. - if (!value) { - return Nothing(); - } - - // 3. Let tokens be contentAttributeValue, split on ASCII whitespace. - MOZ_ASSERT(value->Type() == nsAttrValue::eAtomArray || - value->Type() == nsAttrValue::eAtom, - "Attribute used for attr associated elements must be parsed"); - for (uint32_t i = 0; i < value->GetAtomCount(); i++) { - // For each id of tokens: - if (auto* candidate = GetElementByIdInDocOrSubtree( - value->AtomAt(static_cast(i)))) { - // Append candidate to elements. - elements.AppendElement(candidate); - } - } + nsINode* root = SubtreeRoot(); + for (auto* node = root; node; node = node->GetNextNode(root)) { + if (node->HasID() && node->AsContent()->GetID() == valueAtom) { + return node->AsElement(); } - - return Some(std::move(elements)); - }; - - // getter steps: - // 1. Let elements be the result of running this's get the attr-associated - // elements. - auto elements = getAttrAssociatedElements(); - - if (elements && elements == cachedAttrElements) { - // 2. If the contents of elements is equal to the contents of this's cached - // attr-associated elements, then return this's cached attr-associated - // elements object. - MOZ_ASSERT(!*aUseCachedValue); - *aUseCachedValue = true; - return; } - - // 3. Let elementsAsFrozenArray be elements, converted to a FrozenArray?. - // (the binding code takes aElements and returns it as a FrozenArray) - // 5. Set this's cached attr-associated elements object to - // elementsAsFrozenArray. - // (the binding code stores the attr-associated elements object in a slot) - // 6. Return elementsAsFrozenArray. - if (elements) { - aElements.SetValue(elements->Clone()); - } - - // 4. Set this's cached attr-associated elements to elements. - cachedAttrElements = std::move(elements); + return nullptr; } void Element::ClearExplicitlySetAttrElement(nsAtom* aAttr) { if (auto* slots = GetExistingExtendedDOMSlots()) { - slots->mExplicitlySetAttrElementMap.Remove(aAttr); - } -} - -void Element::ClearExplicitlySetAttrElements(nsAtom* aAttr) { - if (auto* slots = GetExistingExtendedDOMSlots()) { - slots->mAttrElementsMap.Remove(aAttr); + slots->mExplicitlySetAttrElements.Remove(aAttr); } } @@ -1924,7 +1830,7 @@ void Element::ExplicitlySetAttrElement(nsAtom* aAttr, Element* aElement) { #endif SetAttr(aAttr, EmptyString(), IgnoreErrors()); nsExtendedDOMSlots* slots = ExtendedDOMSlots(); - slots->mExplicitlySetAttrElementMap.InsertOrUpdate( + slots->mExplicitlySetAttrElements.InsertOrUpdate( aAttr, do_GetWeakReference(aElement)); #ifdef ACCESSIBILITY if (accService) { @@ -1948,48 +1854,9 @@ void Element::ExplicitlySetAttrElement(nsAtom* aAttr, Element* aElement) { #endif } -void Element::ExplicitlySetAttrElements( - nsAtom* aAttr, - const Nullable>>& aElements) { -#ifdef ACCESSIBILITY - nsAccessibilityService* accService = GetAccService(); -#endif - // Accessibility requires that no other attribute changes occur between - // AttrElementWillChange and AttrElementChanged. Scripts could cause - // this, so don't let them run here. We do this even if accessibility isn't - // running so that the JS behavior is consistent regardless of accessibility. - // Otherwise, JS might be able to use this difference to determine whether - // accessibility is running, which would be a privacy concern. - nsAutoScriptBlocker scriptBlocker; - -#ifdef ACCESSIBILITY - if (accService) { - accService->NotifyAttrElementWillChange(this, aAttr); - } -#endif - - if (aElements.IsNull()) { - ClearExplicitlySetAttrElements(aAttr); - UnsetAttr(aAttr, IgnoreErrors()); - } else { - SetAttr(aAttr, EmptyString(), IgnoreErrors()); - auto& entry = ExtendedDOMSlots()->mAttrElementsMap.LookupOrInsert(aAttr); - entry.first.emplace(nsTArray()); - for (Element* el : aElements.Value()) { - entry.first->AppendElement(do_GetWeakReference(el)); - } - } - -#ifdef ACCESSIBILITY - if (accService) { - accService->NotifyAttrElementChanged(this, aAttr); - } -#endif -} - Element* Element::GetExplicitlySetAttrElement(nsAtom* aAttr) const { if (const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) { - nsWeakPtr weakAttrEl = slots->mExplicitlySetAttrElementMap.Get(aAttr); + nsWeakPtr weakAttrEl = slots->mExplicitlySetAttrElements.Get(aAttr); if (nsCOMPtr attrEl = do_QueryReferent(weakAttrEl)) { return attrEl; } @@ -1997,22 +1864,6 @@ Element* Element::GetExplicitlySetAttrElement(nsAtom* aAttr) const { return nullptr; } -void Element::GetExplicitlySetAttrElements( - nsAtom* aAttr, nsTArray& aElements) const { - if (const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) { - if (auto attrElementsMaybeEntry = slots->mAttrElementsMap.Lookup(aAttr)) { - auto& [attrElements, cachedAttrElements] = attrElementsMaybeEntry.Data(); - if (attrElements) { - for (const nsWeakPtr& weakEl : *attrElements) { - if (nsCOMPtr attrEl = do_QueryReferent(weakEl)) { - aElements.AppendElement(attrEl); - } - } - } - } - } -} - void Element::GetElementsWithGrid(nsTArray>& aElements) { nsINode* cur = this; while (cur) { @@ -2971,14 +2822,7 @@ bool Element::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute, } if (aNamespaceID == kNameSpaceID_None) { - if (aAttribute == nsGkAtoms::_class || aAttribute == nsGkAtoms::part || - aAttribute == nsGkAtoms::aria_controls || - aAttribute == nsGkAtoms::aria_describedby || - aAttribute == nsGkAtoms::aria_details || - aAttribute == nsGkAtoms::aria_errormessage || - aAttribute == nsGkAtoms::aria_flowto || - aAttribute == nsGkAtoms::aria_labelledby || - aAttribute == nsGkAtoms::aria_owns) { + if (aAttribute == nsGkAtoms::_class || aAttribute == nsGkAtoms::part) { aResult.ParseAtomArray(aValue); return true; } @@ -3050,14 +2894,6 @@ void Element::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName, } } else if (aName == nsGkAtoms::aria_activedescendant) { ClearExplicitlySetAttrElement(aName); - } else if (aName == nsGkAtoms::aria_controls || - aName == nsGkAtoms::aria_describedby || - aName == nsGkAtoms::aria_details || - aName == nsGkAtoms::aria_errormessage || - aName == nsGkAtoms::aria_flowto || - aName == nsGkAtoms::aria_labelledby || - aName == nsGkAtoms::aria_owns) { - ClearExplicitlySetAttrElements(aName); } } } @@ -3114,16 +2950,6 @@ void Element::OnAttrSetButNotChanged(int32_t aNamespaceID, nsAtom* aName, aName == nsGkAtoms::aria_activedescendant) { ClearExplicitlySetAttrElement(aName); } - - if (aNamespaceID == kNameSpaceID_None && - (aName == nsGkAtoms::aria_controls || - aName == nsGkAtoms::aria_describedby || - aName == nsGkAtoms::aria_details || - aName == nsGkAtoms::aria_errormessage || - aName == nsGkAtoms::aria_flowto || aName == nsGkAtoms::aria_labelledby || - aName == nsGkAtoms::aria_owns)) { - ClearExplicitlySetAttrElements(aName); - } } EventListenerManager* Element::GetEventListenerManagerForAttr(nsAtom* aAttrName, diff --git a/dom/base/Element.h b/dom/base/Element.h index 7d14de4b8701..f741e2b9bb89 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -266,17 +266,6 @@ class TrustedHTMLOrNullIsEmptyString; ExplicitlySetAttrElement(nsGkAtoms::attr, aElement); \ } -#define REFLECT_NULLABLE_ELEMENTS_ATTR(method, attr) \ - void Get##method(bool* aUseCachedValue, \ - Nullable>>& aElements) { \ - GetAttrAssociatedElements(nsGkAtoms::attr, aUseCachedValue, aElements); \ - } \ - \ - void Set##method( \ - const Nullable>>& aElements) { \ - ExplicitlySetAttrElements(nsGkAtoms::attr, aElements); \ - } - // TODO(keithamus): Reference the spec link once merged. // https://github.com/whatwg/html/pull/9841/files#diff-41cf6794ba4200b839c53531555f0f3998df4cbb01a4d5cb0b94e3ca5e23947dR86024 enum class InvokeAction : uint8_t { @@ -716,28 +705,21 @@ class Element : public FragmentOrElement { REFLECT_NULLABLE_DOMSTRING_ATTR(AriaColIndex, aria_colindex) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaColIndexText, aria_colindextext) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaColSpan, aria_colspan) - REFLECT_NULLABLE_ELEMENTS_ATTR(AriaControlsElements, aria_controls) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaCurrent, aria_current) - REFLECT_NULLABLE_ELEMENTS_ATTR(AriaDescribedByElements, aria_describedby) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaDescription, aria_description) - REFLECT_NULLABLE_ELEMENTS_ATTR(AriaDetailsElements, aria_details) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaDisabled, aria_disabled) - REFLECT_NULLABLE_ELEMENTS_ATTR(AriaErrorMessageElements, aria_errormessage) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaExpanded, aria_expanded) - REFLECT_NULLABLE_ELEMENTS_ATTR(AriaFlowToElements, aria_flowto) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaHasPopup, aria_haspopup) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaHidden, aria_hidden) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaInvalid, aria_invalid) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaKeyShortcuts, aria_keyshortcuts) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaLabel, aria_label) - REFLECT_NULLABLE_ELEMENTS_ATTR(AriaLabelledByElements, aria_labelledby) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaLevel, aria_level) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaLive, aria_live) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaModal, aria_modal) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaMultiLine, aria_multiline) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaMultiSelectable, aria_multiselectable) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaOrientation, aria_orientation) - REFLECT_NULLABLE_ELEMENTS_ATTR(AriaOwnsElements, aria_owns) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaPlaceholder, aria_placeholder) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaPosInSet, aria_posinset) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaPressed, aria_pressed) @@ -1189,10 +1171,6 @@ class Element : public FragmentOrElement { const MappedAttributeEntry* const aMaps[], uint32_t aMapCount); - bool HasSharedRoot(const Element* aElement) const; - - Element* GetElementByIdInDocOrSubtree(nsAtom* aID) const; - protected: inline bool GetAttr(const nsAtom* aName, DOMString& aResult) const { MOZ_ASSERT(aResult.IsEmpty(), "Should have empty string coming in"); @@ -1313,21 +1291,14 @@ class Element : public FragmentOrElement { * https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#attr-associated-element */ Element* GetAttrAssociatedElement(nsAtom* aAttr) const; - void GetAttrAssociatedElements( - nsAtom* aAttr, bool* aUseCachedValue, - Nullable>>& aElements); /** * Sets an attribute element for the given attribute. * https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#explicitly-set-attr-element */ void ExplicitlySetAttrElement(nsAtom* aAttr, Element* aElement); - void ExplicitlySetAttrElements( - nsAtom* aAttr, - const Nullable>>& aElements); void ClearExplicitlySetAttrElement(nsAtom*); - void ClearExplicitlySetAttrElements(nsAtom*); /** * Gets the attribute element for the given attribute. @@ -1339,16 +1310,6 @@ class Element : public FragmentOrElement { */ Element* GetExplicitlySetAttrElement(nsAtom* aAttr) const; - /** - * Gets the attribute elements for the given attribute. Unlike - * GetAttrAssociatedElements, this returns an uncached array of explicitly set - * elements without checking if they are a descendant of any of this element's - * shadow-including ancestors. It also does not attempt to retrieve elements - * using the ids set in the content attribute. - */ - void GetExplicitlySetAttrElements(nsAtom* aAttr, - nsTArray& aElements) const; - PseudoStyleType GetPseudoElementType() const { nsresult rv = NS_OK; auto raw = GetProperty(nsGkAtoms::pseudoProperty, &rv); diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index 737ed8883d19..995e9d792a25 100644 --- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -637,8 +637,7 @@ void FragmentOrElement::nsExtendedDOMSlots::UnlinkExtendedSlots( mAnimations = nullptr; aContent.ClearMayHaveAnimations(); } - mExplicitlySetAttrElementMap.Clear(); - mAttrElementsMap.Clear(); + mExplicitlySetAttrElements.Clear(); mRadioGroupContainer = nullptr; mPart = nullptr; } @@ -662,15 +661,6 @@ void FragmentOrElement::nsExtendedDOMSlots::TraverseExtendedSlots( NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mSlots->mPart"); aCb.NoteXPCOMChild(mPart.get()); - for (auto& tableEntry : mAttrElementsMap) { - auto& [explicitlySetElements, cachedAttrElements] = - *tableEntry.GetModifiableData(); - if (cachedAttrElements) { - ImplCycleCollectionTraverse(aCb, *cachedAttrElements, - "cached attribute elements entry", 0); - } - } - if (mCustomElementData) { mCustomElementData->Traverse(aCb); } diff --git a/dom/base/FragmentOrElement.h b/dom/base/FragmentOrElement.h index afa155d3a96d..8358f424a1c1 100644 --- a/dom/base/FragmentOrElement.h +++ b/dom/base/FragmentOrElement.h @@ -268,21 +268,10 @@ class FragmentOrElement : public nsIContent { RefPtr mPart; /** - * Explicitly set attr-element, see + * Explicitly set attr-elements, see * https://html.spec.whatwg.org/#explicitly-set-attr-element */ - nsTHashMap, nsWeakPtr> mExplicitlySetAttrElementMap; - /** - * Explicitly set attr-elements, see - * https://html.spec.whatwg.org/#explicitly-set-attr-elements - * - * The first member of the pair are the explicitly set attr-elements. The - * second member is the cached attr-associated elements. - */ - - nsTHashMap, std::pair>, - Maybe>>>> - mAttrElementsMap; + nsTHashMap, nsWeakPtr> mExplicitlySetAttrElements; }; class nsDOMSlots : public nsIContent::nsContentSlots { diff --git a/dom/html/ElementInternals.cpp b/dom/html/ElementInternals.cpp index 0f6cc11b865d..b0cf05617dc5 100644 --- a/dom/html/ElementInternals.cpp +++ b/dom/html/ElementInternals.cpp @@ -41,13 +41,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ElementInternals) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTarget, mSubmissionValue, mState, mValidity, mValidationAnchor, mCustomStateSet); - - for (auto& tableEntry : tmp->mAttrElementsMap) { - auto& [explicitlySetElements, cachedAttrElements] = - *tableEntry.GetModifiableData(); - ImplCycleCollectionTraverse(cb, cachedAttrElements, - "cached attribute elements entry", 0); - } NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTING_ADDREF(ElementInternals) @@ -435,7 +428,6 @@ void ElementInternals::Unlink() { mFieldSet->RemoveElement(mTarget); mFieldSet = nullptr; } - mAttrElementsMap.Clear(); } void ElementInternals::GetAttr(const nsAtom* aName, nsAString& aResult) const { @@ -477,23 +469,6 @@ nsresult ElementInternals::SetAttr(nsAtom* aName, const nsAString& aValue) { return rs; } -nsresult ElementInternals::SetAttrInternal(nsAtom* aName, - const nsAString& aValue) { - bool attrHadValue; - nsAttrValue attrValue(aValue); - return mAttrs.SetAndSwapAttr(aName, attrValue, &attrHadValue); -} - -nsresult ElementInternals::UnsetAttrInternal(nsAtom* aName) { - nsAttrValue attrValue; - auto attrPos = mAttrs.IndexOfAttr(aName); - if (attrPos >= 0) { - return mAttrs.RemoveAttrAt(attrPos, attrValue); - } - - return NS_OK; -} - DocGroup* ElementInternals::GetDocGroup() { return mTarget->OwnerDoc()->GetDocGroup(); } @@ -541,11 +516,9 @@ void ElementInternals::SetAttrElement(nsAtom* aAttr, Element* aElement) { #endif if (aElement) { - mAttrElementMap.InsertOrUpdate(aAttr, do_GetWeakReference(aElement)); - SetAttrInternal(aAttr, EmptyString()); + mAttrElements.InsertOrUpdate(aAttr, do_GetWeakReference(aElement)); } else { - mAttrElementMap.Remove(aAttr); - UnsetAttrInternal(aAttr); + mAttrElements.Remove(aAttr); } #ifdef ACCESSIBILITY @@ -556,121 +529,9 @@ void ElementInternals::SetAttrElement(nsAtom* aAttr, Element* aElement) { } Element* ElementInternals::GetAttrElement(nsAtom* aAttr) const { - nsWeakPtr weakAttrEl = mAttrElementMap.Get(aAttr); + nsWeakPtr weakAttrEl = mAttrElements.Get(aAttr); nsCOMPtr attrEl = do_QueryReferent(weakAttrEl); return attrEl; } -void ElementInternals::SetAttrElements( - nsAtom* aAttr, - const Nullable>>& aElements) { -#ifdef ACCESSIBILITY - nsAccessibilityService* accService = GetAccService(); -#endif - // Accessibility requires that no other attribute changes occur between - // AttrElementWillChange and AttrElementChanged. Scripts could cause - // this, so don't let them run here. We do this even if accessibility isn't - // running so that the JS behavior is consistent regardless of accessibility. - // Otherwise, JS might be able to use this difference to determine whether - // accessibility is running, which would be a privacy concern. - nsAutoScriptBlocker scriptBlocker; -#ifdef ACCESSIBILITY - if (accService) { - accService->NotifyAttrElementWillChange(mTarget, aAttr); - } -#endif - - nsAttrValue emptyAttr; - if (aElements.IsNull()) { - mAttrElementsMap.Remove(aAttr); - UnsetAttrInternal(aAttr); - } else { - auto& [attrElements, cachedAttrElements] = - mAttrElementsMap.LookupOrInsert(aAttr); - attrElements.Clear(); - for (Element* el : aElements.Value()) { - attrElements.AppendElement(do_GetWeakReference(el)); - } - SetAttrInternal(aAttr, EmptyString()); - } - -#ifdef ACCESSIBILITY - if (accService) { - accService->NotifyAttrElementChanged(mTarget, aAttr); - } -#endif -} - -void ElementInternals::GetAttrElements( - nsAtom* aAttr, bool* aUseCachedValue, - Nullable>>& aElements) { - MOZ_ASSERT(aElements.IsNull()); - - auto attrElementsMaybeEntry = mAttrElementsMap.Lookup(aAttr); - if (!attrElementsMaybeEntry) { - return; - } - - aElements.SetValue(nsTArray>()); - auto& [attrElements, cachedAttrElements] = attrElementsMaybeEntry.Data(); - - auto getAttrAssociatedElements = [&, &attrElements = attrElements]() { - CopyableTArray> elements; - - for (const nsWeakPtr& weakEl : attrElements) { - // For each attrElement in reflectedTarget's explicitly set attr-elements: - if (nsCOMPtr attrEl = do_QueryReferent(weakEl)) { - // Append attrElement to elements. - elements.AppendElement(attrEl); - } - } - - return elements; - }; - - // https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#attr-associated-elements - // Getter steps: - // 1. Let elements be the result of running this's get the attr-associated - // elements. - auto elements = getAttrAssociatedElements(); - - if (elements == cachedAttrElements) { - // 2. If the contents of elements is equal to the contents of this's cached - // attr-associated elements, then return this's cached attr-associated - // elements object. - MOZ_ASSERT(!*aUseCachedValue); - *aUseCachedValue = true; - return; - } - - // 3. Let elementsAsFrozenArray be elements, converted to a FrozenArray?. - // (the binding code takes aElements and returns it as a FrozenArray) - // 5. Set this's cached attr-associated elements object to - // elementsAsFrozenArray. - // (the binding code stores the attr-associated elements object in a slot) - // 6. Return elementsAsFrozenArray. - aElements.SetValue(elements.Clone()); - - // 4. Set this's cached attr-associated elements to elements. - cachedAttrElements = std::move(elements); -} - -bool ElementInternals::GetAttrElements(nsAtom* aAttr, - nsTArray& aElements) { - aElements.Clear(); - auto attrElementsMaybeEntry = mAttrElementsMap.Lookup(aAttr); - if (!attrElementsMaybeEntry) { - return false; - } - - auto& [attrElements, cachedAttrElements] = attrElementsMaybeEntry.Data(); - for (const nsWeakPtr& weakEl : attrElements) { - if (nsCOMPtr attrEl = do_QueryReferent(weakEl)) { - aElements.AppendElement(attrEl); - } - } - - return true; -} - } // namespace mozilla::dom diff --git a/dom/html/ElementInternals.h b/dom/html/ElementInternals.h index ab4658fa338b..4bbf5c96f383 100644 --- a/dom/html/ElementInternals.h +++ b/dom/html/ElementInternals.h @@ -34,17 +34,6 @@ SetAttrElement(nsGkAtoms::attr, aElement); \ } -#define ARIA_REFLECT_ATTR_ELEMENTS(method, attr) \ - void Get##method(bool* aUseCachedValue, \ - Nullable>>& aElements) { \ - GetAttrElements(nsGkAtoms::attr, aUseCachedValue, aElements); \ - } \ - \ - void Set##method( \ - const Nullable>>& aElements) { \ - SetAttrElements(nsGkAtoms::attr, aElements); \ - } - class nsINodeList; class nsGenericHTMLElement; @@ -148,28 +137,21 @@ class ElementInternals final : public nsIFormControl, ARIA_REFLECT_ATTR(AriaColIndex, aria_colindex) ARIA_REFLECT_ATTR(AriaColIndexText, aria_colindextext) ARIA_REFLECT_ATTR(AriaColSpan, aria_colspan) - ARIA_REFLECT_ATTR_ELEMENTS(AriaControlsElements, aria_controls) ARIA_REFLECT_ATTR(AriaCurrent, aria_current) - ARIA_REFLECT_ATTR_ELEMENTS(AriaDescribedByElements, aria_describedby) ARIA_REFLECT_ATTR(AriaDescription, aria_description) - ARIA_REFLECT_ATTR_ELEMENTS(AriaDetailsElements, aria_details) ARIA_REFLECT_ATTR(AriaDisabled, aria_disabled) - ARIA_REFLECT_ATTR_ELEMENTS(AriaErrorMessageElements, aria_errormessage) ARIA_REFLECT_ATTR(AriaExpanded, aria_expanded) - ARIA_REFLECT_ATTR_ELEMENTS(AriaFlowToElements, aria_flowto) ARIA_REFLECT_ATTR(AriaHasPopup, aria_haspopup) ARIA_REFLECT_ATTR(AriaHidden, aria_hidden) ARIA_REFLECT_ATTR(AriaInvalid, aria_invalid) ARIA_REFLECT_ATTR(AriaKeyShortcuts, aria_keyshortcuts) ARIA_REFLECT_ATTR(AriaLabel, aria_label) - ARIA_REFLECT_ATTR_ELEMENTS(AriaLabelledByElements, aria_labelledby) ARIA_REFLECT_ATTR(AriaLevel, aria_level) ARIA_REFLECT_ATTR(AriaLive, aria_live) ARIA_REFLECT_ATTR(AriaModal, aria_modal) ARIA_REFLECT_ATTR(AriaMultiLine, aria_multiline) ARIA_REFLECT_ATTR(AriaMultiSelectable, aria_multiselectable) ARIA_REFLECT_ATTR(AriaOrientation, aria_orientation) - ARIA_REFLECT_ATTR_ELEMENTS(AriaOwnsElements, aria_owns) ARIA_REFLECT_ATTR(AriaPlaceholder, aria_placeholder) ARIA_REFLECT_ATTR(AriaPosInSet, aria_posinset) ARIA_REFLECT_ATTR(AriaPressed, aria_pressed) @@ -193,8 +175,6 @@ class ElementInternals final : public nsIFormControl, nsresult SetAttr(nsAtom* aName, const nsAString& aValue); - bool GetAttrElements(nsAtom* aAttr, nsTArray& aElements); - const AttrArray& GetAttrs() const { return mAttrs; } DocGroup* GetDocGroup(); @@ -214,17 +194,6 @@ class ElementInternals final : public nsIFormControl, */ void SetAttrElement(nsAtom* aAttr, Element* aElement); - void SetAttrElements( - nsAtom* aAttr, - const Nullable>>& aElements); - - void GetAttrElements(nsAtom* aAttr, bool* aUseCachedValue, - Nullable>>& aElements); - - nsresult SetAttrInternal(nsAtom* aName, const nsAString& aValue); - - nsresult UnsetAttrInternal(nsAtom* aName); - // It's a target element which is a custom element. RefPtr mTarget; @@ -269,11 +238,7 @@ class ElementInternals final : public nsIFormControl, * Explicitly set attr-elements, see * https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#explicitly-set-attr-element */ - nsTHashMap, nsWeakPtr> mAttrElementMap; - - nsTHashMap, - std::pair, nsTArray>>> - mAttrElementsMap; + nsTHashMap, nsWeakPtr> mAttrElements; }; } // namespace mozilla::dom diff --git a/dom/webidl/ARIAMixin.webidl b/dom/webidl/ARIAMixin.webidl index 6285549bd961..10d23af96e38 100644 --- a/dom/webidl/ARIAMixin.webidl +++ b/dom/webidl/ARIAMixin.webidl @@ -47,38 +47,18 @@ interface mixin ARIAMixin { [CEReactions, SetterThrows] attribute DOMString? ariaColSpan; - // TODO: Use FrozenArray once available. (Bug 1236777) - [Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray] - attribute sequence? ariaControlsElements; - [CEReactions, SetterThrows] attribute DOMString? ariaCurrent; - // TODO: Use FrozenArray once available. (Bug 1236777) - [Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray] - attribute sequence? ariaDescribedByElements; - [CEReactions, SetterThrows] attribute DOMString? ariaDescription; - // TODO: Use FrozenArray once available. (Bug 1236777) - [Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray] - attribute sequence? ariaDetailsElements; - [CEReactions, SetterThrows] attribute DOMString? ariaDisabled; - // TODO: Use FrozenArray once available. (Bug 1236777) - [Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray] - attribute sequence? ariaErrorMessageElements; - [CEReactions, SetterThrows] attribute DOMString? ariaExpanded; - // TODO: Use FrozenArray once available. (Bug 1236777) - [Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray] - attribute sequence? ariaFlowToElements; - [CEReactions, SetterThrows] attribute DOMString? ariaHasPopup; @@ -94,10 +74,6 @@ interface mixin ARIAMixin { [CEReactions, SetterThrows] attribute DOMString? ariaLabel; - // TODO: Use FrozenArray once available. (Bug 1236777) - [Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray] - attribute sequence? ariaLabelledByElements; - [CEReactions, SetterThrows] attribute DOMString? ariaLevel; @@ -116,10 +92,6 @@ interface mixin ARIAMixin { [CEReactions, SetterThrows] attribute DOMString? ariaOrientation; - // TODO: Use FrozenArray once available. (Bug 1236777) - [Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray] - attribute sequence? ariaOwnsElements; - [CEReactions, SetterThrows] attribute DOMString? ariaPlaceholder; diff --git a/testing/web-platform/meta/custom-elements/ElementInternals-accessibility.html.ini b/testing/web-platform/meta/custom-elements/ElementInternals-accessibility.html.ini index 714c773981d6..b6e14a3b383d 100644 --- a/testing/web-platform/meta/custom-elements/ElementInternals-accessibility.html.ini +++ b/testing/web-platform/meta/custom-elements/ElementInternals-accessibility.html.ini @@ -1,2 +1,23 @@ [ElementInternals-accessibility.html] prefs: [accessibility.ARIAElementReflection.enabled:true] + [ariaControlsElements is defined in ElementInternals] + expected: FAIL + + [ariaDescribedByElements is defined in ElementInternals] + expected: FAIL + + [ariaDetailsElements is defined in ElementInternals] + expected: FAIL + + [ariaFlowToElements is defined in ElementInternals] + expected: FAIL + + [ariaLabelledByElements is defined in ElementInternals] + expected: FAIL + + [ariaOwnsElements is defined in ElementInternals] + expected: FAIL + + [ariaErrorMessageElements is defined in ElementInternals] + expected: FAIL + diff --git a/testing/web-platform/meta/custom-elements/element-internals-aria-element-reflection.html.ini b/testing/web-platform/meta/custom-elements/element-internals-aria-element-reflection.html.ini index bb15d94758ca..f250b693feb1 100644 --- a/testing/web-platform/meta/custom-elements/element-internals-aria-element-reflection.html.ini +++ b/testing/web-platform/meta/custom-elements/element-internals-aria-element-reflection.html.ini @@ -1,5 +1,6 @@ [element-internals-aria-element-reflection.html] - prefs: [accessibility.ARIAElementReflection.enabled:true] + [Getting previously-unset ARIA element reflection properties on ElementInternals should return null.] + expected: FAIL [Setting ariaLabelledByElements should change the accessible name of the custom element] expected: FAIL diff --git a/testing/web-platform/meta/html/dom/aria-element-reflection-disconnected.html.ini b/testing/web-platform/meta/html/dom/aria-element-reflection-disconnected.html.ini index 36b2af471f0b..b6fd46a4a26d 100644 --- a/testing/web-platform/meta/html/dom/aria-element-reflection-disconnected.html.ini +++ b/testing/web-platform/meta/html/dom/aria-element-reflection-disconnected.html.ini @@ -1,2 +1,4 @@ [aria-element-reflection-disconnected.html] prefs: [accessibility.ARIAElementReflection.enabled:true] + [Element references should stay valid when content is disconnected (element array)] + expected: FAIL diff --git a/testing/web-platform/meta/html/dom/aria-element-reflection-labelledby.html.ini b/testing/web-platform/meta/html/dom/aria-element-reflection-labelledby.html.ini new file mode 100644 index 000000000000..1abd7270d545 --- /dev/null +++ b/testing/web-platform/meta/html/dom/aria-element-reflection-labelledby.html.ini @@ -0,0 +1,12 @@ +[aria-element-reflection-labelledby.html] + [Setting ariaLabelledByElements should determine the computed label for the labelled element] + expected: FAIL + + [Setting ariaLabelledByElements before inserting the elements referred to in the document should cause the label to be updated once elements are inserted] + expected: FAIL + + [Setting ariaLabelledByElements on an element before inserting it in the document should cause the label to be updated once the element is inserted] + expected: FAIL + + [Moving the label from shadow DOM to light DOM causes the reference to become valid] + expected: FAIL diff --git a/testing/web-platform/meta/html/dom/aria-element-reflection.html.ini b/testing/web-platform/meta/html/dom/aria-element-reflection.html.ini index ee795001c32e..6a58d0b94cd7 100644 --- a/testing/web-platform/meta/html/dom/aria-element-reflection.html.ini +++ b/testing/web-platform/meta/html/dom/aria-element-reflection.html.ini @@ -1,2 +1,34 @@ [aria-element-reflection.html] prefs: [accessibility.ARIAElementReflection.enabled:true] + [aria-errormessage] + expected: FAIL + + [aria-details] + expected: FAIL + + [aria-labelledby.] + expected: FAIL + + [aria-controls.] + expected: FAIL + + [aria-describedby.] + expected: FAIL + + [aria-flowto.] + expected: FAIL + + [aria-owns.] + expected: FAIL + + [shadow DOM behaviour for FrozenArray element reflection.] + expected: FAIL + + [Moving explicitly set elements across shadow DOM boundaries.] + expected: FAIL + + [Moving explicitly set elements around within the same scope, and removing from the DOM.] + expected: FAIL + + [Passing values of the wrong type should throw a TypeError] + expected: FAIL diff --git a/testing/web-platform/meta/wai-aria/idlharness.window.js.ini b/testing/web-platform/meta/wai-aria/idlharness.window.js.ini index 7298bc33c4a9..f4edcb4562ac 100644 --- a/testing/web-platform/meta/wai-aria/idlharness.window.js.ini +++ b/testing/web-platform/meta/wai-aria/idlharness.window.js.ini @@ -1,2 +1,43 @@ [idlharness.window.html] prefs: [accessibility.ARIAElementReflection.enabled:true] + [Element interface: attribute ariaControlsElements] + expected: FAIL + + [Element interface: attribute ariaDescribedByElements] + expected: FAIL + + [Element interface: attribute ariaDetailsElements] + expected: FAIL + + [Element interface: attribute ariaFlowToElements] + expected: FAIL + + [Element interface: attribute ariaLabelledByElements] + expected: FAIL + + [Element interface: attribute ariaOwnsElements] + expected: FAIL + + [Element interface: element must inherit property "ariaControlsElements" with the proper type] + expected: FAIL + + [Element interface: element must inherit property "ariaDescribedByElements" with the proper type] + expected: FAIL + + [Element interface: element must inherit property "ariaDetailsElements" with the proper type] + expected: FAIL + + [Element interface: element must inherit property "ariaFlowToElements" with the proper type] + expected: FAIL + + [Element interface: element must inherit property "ariaLabelledByElements" with the proper type] + expected: FAIL + + [Element interface: element must inherit property "ariaOwnsElements" with the proper type] + expected: FAIL + + [Element interface: attribute ariaErrorMessageElements] + expected: FAIL + + [Element interface: element must inherit property "ariaErrorMessageElements" with the proper type] + expected: FAIL