mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
Backed out 3 changesets (bug 1769586) for causing bug 1920082. a=backout
Backed out changeset d684010261d6 (bug 1769586) Backed out changeset b3264bc533e2 (bug 1769586) Backed out changeset 049fd286ce0f (bug 1769586)
This commit is contained in:
parent
2613e8be8e
commit
004d210bbf
@ -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<int32_t>(ArrayLength(gWAIUnivAttrMap));
|
||||
mIdx++) {
|
||||
if (gWAIUnivAttrMap[mIdx].characteristics & mCharacteristics) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsStaticAtom* AttrWithCharacteristicsIterator::AttrName() const {
|
||||
return mIdx >= 0
|
||||
? const_cast<nsStaticAtom*>(gWAIUnivAttrMap[mIdx].attributeName)
|
||||
: nullptr;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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<dom::Element*> mElements;
|
||||
uint32_t mElemIdx;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -340,7 +340,7 @@ UniquePtr<AccIterable> CachedTableCellAccessible::GetExplicitHeadersIterator() {
|
||||
}
|
||||
}
|
||||
} else if (LocalAccessible* localAcc = mAcc->AsLocal()) {
|
||||
return MakeUnique<AssociatedElementsIterator>(
|
||||
return MakeUnique<IDRefsIterator>(
|
||||
localAcc->Document(), localAcc->GetContent(), nsGkAtoms::headers);
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -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<dom::Element*>& 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) {
|
||||
|
@ -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<dom::Element*>& aElements);
|
||||
static bool ARIAAttrValueIs(dom::Element* aElement, const nsAtom* aName,
|
||||
const nsAString& aValue,
|
||||
nsCaseTreatment aCaseSensitive);
|
||||
|
@ -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 += ' ';
|
||||
|
||||
|
@ -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()) {
|
||||
@ -1240,7 +1240,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);
|
||||
}
|
||||
}
|
||||
@ -1802,7 +1802,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;
|
||||
@ -1845,7 +1845,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;
|
||||
@ -1891,28 +1891,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<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 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,
|
||||
@ -1943,34 +1921,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<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 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,
|
||||
@ -2449,7 +2399,7 @@ void DocAccessible::DoARIAOwnsRelocation(LocalAccessible* aOwner) {
|
||||
nsTArray<RefPtr<LocalAccessible>>* 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);
|
||||
|
@ -196,8 +196,7 @@ already_AddRefed<nsIURI> 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)) &&
|
||||
|
@ -1416,7 +1416,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);
|
||||
}
|
||||
@ -1426,7 +1426,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);
|
||||
@ -1442,7 +1442,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);
|
||||
}
|
||||
@ -1461,7 +1461,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);
|
||||
}
|
||||
@ -2173,8 +2173,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));
|
||||
}
|
||||
@ -2187,16 +2187,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));
|
||||
}
|
||||
@ -2212,8 +2211,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;
|
||||
@ -2292,15 +2290,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(
|
||||
@ -2450,10 +2448,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);
|
||||
@ -2480,8 +2477,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(
|
||||
@ -3995,7 +3992,7 @@ already_AddRefed<AccAttributes> LocalAccessible::BundleFieldsForCache(
|
||||
}
|
||||
if (mContent->AsElement()->HasAttr(nsGkAtoms::headers)) {
|
||||
nsTArray<uint64_t> 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());
|
||||
@ -4066,12 +4063,11 @@ already_AddRefed<AccAttributes> 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()) {
|
||||
|
@ -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;
|
||||
|
@ -467,247 +467,3 @@ between
|
||||
},
|
||||
{ chrome: true, topLevel: true }
|
||||
);
|
||||
|
||||
/**
|
||||
* Test relation defaults via element internals
|
||||
*/
|
||||
addAccessibleTask(
|
||||
`
|
||||
<div id="dependant1">label</div>
|
||||
<custom-checkbox id="host"></custom-checkbox>
|
||||
<div id="dependant2">label2</div>
|
||||
|
||||
<script>
|
||||
customElements.define("custom-checkbox",
|
||||
class extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.tabIndex = "0";
|
||||
this._internals = this.attachInternals();
|
||||
this._internals.role = "checkbox";
|
||||
this._internals.ariaChecked = "true";
|
||||
}
|
||||
get internals() {
|
||||
return this._internals;
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>`,
|
||||
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(
|
||||
`
|
||||
<div id="describedButtonContainer">
|
||||
<div id="buttonDescription1">Delicious</div>
|
||||
<div id="buttonDescription2">Nutritious</div>
|
||||
<div id="outerShadowHost"></div>
|
||||
<button id="describedElement">Button</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const buttonDescription1 = document.getElementById("buttonDescription1");
|
||||
const buttonDescription2 = document.getElementById("buttonDescription2");
|
||||
const outerShadowRoot = outerShadowHost.attachShadow({mode: "open"});
|
||||
const innerShadowHost = document.createElement("div");
|
||||
outerShadowRoot.appendChild(innerShadowHost);
|
||||
const innerShadowRoot = innerShadowHost.attachShadow({mode: "open"});
|
||||
|
||||
const describedElement = document.getElementById("describedElement");
|
||||
// Add some attr associated light DOM elements.
|
||||
describedElement.ariaDescribedByElements = [buttonDescription1, buttonDescription2];
|
||||
</script>`,
|
||||
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,
|
||||
]);
|
||||
}
|
||||
);
|
||||
|
@ -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(
|
||||
@ -507,44 +456,6 @@ addAccessibleTask(
|
||||
{ chrome: false, iframe: true, remoteIframe: true }
|
||||
);
|
||||
|
||||
/**
|
||||
* Test relation defaults via element internals
|
||||
*/
|
||||
addAccessibleTask(
|
||||
`
|
||||
|
||||
<div role="listbox">
|
||||
<div role="listitem" id="l1"></div>
|
||||
<div role="listitem" id="l2"></div>
|
||||
<div role="listitem" id="l3"></div>
|
||||
</div>
|
||||
<custom-listbox id="listbox"></custom-listbox>
|
||||
<div role="listbox">
|
||||
<div role="listitem" id="l4"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
customElements.define("custom-listbox",
|
||||
class extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.tabIndex = "0"
|
||||
this._internals = this.attachInternals();
|
||||
this._internals.role = "listbox";
|
||||
this._internals.ariaOwnsElements = Array.from(this.previousElementSibling.children)
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>`,
|
||||
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;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Test insertion of relocated by ID child after initial load
|
||||
*/
|
||||
|
@ -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]);
|
||||
|
@ -1755,40 +1755,25 @@ already_AddRefed<nsIHTMLCollection> 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<Element> 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;
|
||||
}
|
||||
}
|
||||
@ -1801,102 +1786,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<nsTArray<RefPtr<Element>>>& 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<RefPtr<Element>>> {
|
||||
nsTArray<RefPtr<Element>> 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<Element> 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<int32_t>(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<T>?.
|
||||
// (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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1919,7 +1825,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) {
|
||||
@ -1943,48 +1849,9 @@ void Element::ExplicitlySetAttrElement(nsAtom* aAttr, Element* aElement) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void Element::ExplicitlySetAttrElements(
|
||||
nsAtom* aAttr,
|
||||
const Nullable<Sequence<OwningNonNull<Element>>>& 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<nsWeakPtr>());
|
||||
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<Element> attrEl = do_QueryReferent(weakAttrEl)) {
|
||||
return attrEl;
|
||||
}
|
||||
@ -1992,22 +1859,6 @@ Element* Element::GetExplicitlySetAttrElement(nsAtom* aAttr) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Element::GetExplicitlySetAttrElements(
|
||||
nsAtom* aAttr, nsTArray<Element*>& 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<Element> attrEl = do_QueryReferent(weakEl)) {
|
||||
aElements.AppendElement(attrEl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Element::GetElementsWithGrid(nsTArray<RefPtr<Element>>& aElements) {
|
||||
nsINode* cur = this;
|
||||
while (cur) {
|
||||
@ -2966,14 +2817,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;
|
||||
}
|
||||
@ -3045,14 +2889,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3109,16 +2945,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,
|
||||
|
@ -263,17 +263,6 @@ class Grid;
|
||||
ExplicitlySetAttrElement(nsGkAtoms::attr, aElement); \
|
||||
}
|
||||
|
||||
#define REFLECT_NULLABLE_ELEMENTS_ATTR(method, attr) \
|
||||
void Get##method(bool* aUseCachedValue, \
|
||||
Nullable<nsTArray<RefPtr<Element>>>& aElements) { \
|
||||
GetAttrAssociatedElements(nsGkAtoms::attr, aUseCachedValue, aElements); \
|
||||
} \
|
||||
\
|
||||
void Set##method( \
|
||||
const Nullable<Sequence<OwningNonNull<Element>>>& 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 {
|
||||
@ -713,28 +702,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)
|
||||
@ -1186,10 +1168,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");
|
||||
@ -1307,21 +1285,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<nsTArray<RefPtr<Element>>>& 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<Sequence<OwningNonNull<Element>>>& aElements);
|
||||
|
||||
void ClearExplicitlySetAttrElement(nsAtom*);
|
||||
void ClearExplicitlySetAttrElements(nsAtom*);
|
||||
|
||||
/**
|
||||
* Gets the attribute element for the given attribute.
|
||||
@ -1333,16 +1304,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<Element*>& aElements) const;
|
||||
|
||||
PseudoStyleType GetPseudoElementType() const {
|
||||
nsresult rv = NS_OK;
|
||||
auto raw = GetProperty(nsGkAtoms::pseudoProperty, &rv);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -268,21 +268,10 @@ class FragmentOrElement : public nsIContent {
|
||||
RefPtr<nsDOMTokenList> mPart;
|
||||
|
||||
/**
|
||||
* Explicitly set attr-element, see
|
||||
* Explicitly set attr-elements, see
|
||||
* https://html.spec.whatwg.org/#explicitly-set-attr-element
|
||||
*/
|
||||
nsTHashMap<RefPtr<nsAtom>, 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<RefPtr<nsAtom>, std::pair<Maybe<nsTArray<nsWeakPtr>>,
|
||||
Maybe<nsTArray<RefPtr<Element>>>>>
|
||||
mAttrElementsMap;
|
||||
nsTHashMap<RefPtr<nsAtom>, nsWeakPtr> mExplicitlySetAttrElements;
|
||||
};
|
||||
|
||||
class nsDOMSlots : public nsIContent::nsContentSlots {
|
||||
|
@ -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<Element> attrEl = do_QueryReferent(weakAttrEl);
|
||||
return attrEl;
|
||||
}
|
||||
|
||||
void ElementInternals::SetAttrElements(
|
||||
nsAtom* aAttr,
|
||||
const Nullable<Sequence<OwningNonNull<Element>>>& 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<nsTArray<RefPtr<Element>>>& aElements) {
|
||||
MOZ_ASSERT(aElements.IsNull());
|
||||
|
||||
auto attrElementsMaybeEntry = mAttrElementsMap.Lookup(aAttr);
|
||||
if (!attrElementsMaybeEntry) {
|
||||
return;
|
||||
}
|
||||
|
||||
aElements.SetValue(nsTArray<RefPtr<Element>>());
|
||||
auto& [attrElements, cachedAttrElements] = attrElementsMaybeEntry.Data();
|
||||
|
||||
auto getAttrAssociatedElements = [&, &attrElements = attrElements]() {
|
||||
CopyableTArray<RefPtr<Element>> elements;
|
||||
|
||||
for (const nsWeakPtr& weakEl : attrElements) {
|
||||
// For each attrElement in reflectedTarget's explicitly set attr-elements:
|
||||
if (nsCOMPtr<Element> 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<T>?.
|
||||
// (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<Element*>& aElements) {
|
||||
aElements.Clear();
|
||||
auto attrElementsMaybeEntry = mAttrElementsMap.Lookup(aAttr);
|
||||
if (!attrElementsMaybeEntry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& [attrElements, cachedAttrElements] = attrElementsMaybeEntry.Data();
|
||||
for (const nsWeakPtr& weakEl : attrElements) {
|
||||
if (nsCOMPtr<Element> attrEl = do_QueryReferent(weakEl)) {
|
||||
aElements.AppendElement(attrEl);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
@ -34,17 +34,6 @@
|
||||
SetAttrElement(nsGkAtoms::attr, aElement); \
|
||||
}
|
||||
|
||||
#define ARIA_REFLECT_ATTR_ELEMENTS(method, attr) \
|
||||
void Get##method(bool* aUseCachedValue, \
|
||||
Nullable<nsTArray<RefPtr<Element>>>& aElements) { \
|
||||
GetAttrElements(nsGkAtoms::attr, aUseCachedValue, aElements); \
|
||||
} \
|
||||
\
|
||||
void Set##method( \
|
||||
const Nullable<Sequence<OwningNonNull<Element>>>& 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<Element*>& 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<Sequence<OwningNonNull<Element>>>& aElements);
|
||||
|
||||
void GetAttrElements(nsAtom* aAttr, bool* aUseCachedValue,
|
||||
Nullable<nsTArray<RefPtr<Element>>>& aElements);
|
||||
|
||||
nsresult SetAttrInternal(nsAtom* aName, const nsAString& aValue);
|
||||
|
||||
nsresult UnsetAttrInternal(nsAtom* aName);
|
||||
|
||||
// It's a target element which is a custom element.
|
||||
RefPtr<HTMLElement> 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<RefPtr<nsAtom>, nsWeakPtr> mAttrElementMap;
|
||||
|
||||
nsTHashMap<RefPtr<nsAtom>,
|
||||
std::pair<nsTArray<nsWeakPtr>, nsTArray<RefPtr<Element>>>>
|
||||
mAttrElementsMap;
|
||||
nsTHashMap<RefPtr<nsAtom>, nsWeakPtr> mAttrElements;
|
||||
};
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
@ -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<Element>? ariaControlsElements;
|
||||
|
||||
[CEReactions, SetterThrows]
|
||||
attribute DOMString? ariaCurrent;
|
||||
|
||||
// TODO: Use FrozenArray once available. (Bug 1236777)
|
||||
[Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray]
|
||||
attribute sequence<Element>? ariaDescribedByElements;
|
||||
|
||||
[CEReactions, SetterThrows]
|
||||
attribute DOMString? ariaDescription;
|
||||
|
||||
// TODO: Use FrozenArray once available. (Bug 1236777)
|
||||
[Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray]
|
||||
attribute sequence<Element>? ariaDetailsElements;
|
||||
|
||||
[CEReactions, SetterThrows]
|
||||
attribute DOMString? ariaDisabled;
|
||||
|
||||
// TODO: Use FrozenArray once available. (Bug 1236777)
|
||||
[Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray]
|
||||
attribute sequence<Element>? ariaErrorMessageElements;
|
||||
|
||||
[CEReactions, SetterThrows]
|
||||
attribute DOMString? ariaExpanded;
|
||||
|
||||
// TODO: Use FrozenArray once available. (Bug 1236777)
|
||||
[Pref="accessibility.ARIAElementReflection.enabled", Frozen, ReflectedHTMLAttributeReturningFrozenArray]
|
||||
attribute sequence<Element>? 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<Element>? 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<Element>? ariaOwnsElements;
|
||||
|
||||
[CEReactions, SetterThrows]
|
||||
attribute DOMString? ariaPlaceholder;
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -1,2 +1,3 @@
|
||||
[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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user