Bug 1774043: [Part 1] Add cache domains, caching logic for LABEL_FOR and LABELLED_BY relations r=Jamie

Differential Revision: https://phabricator.services.mozilla.com/D152100
This commit is contained in:
Morgan Rae Reschenberg 2022-08-02 02:51:03 +00:00
parent 89d63c91e6
commit 4d3f82861a
3 changed files with 64 additions and 0 deletions

View File

@ -7,6 +7,8 @@
#ifndef _CacheConstants_h_
#define _CacheConstants_h_
#include "RelationType.h"
namespace mozilla {
namespace a11y {
@ -28,6 +30,7 @@ class CacheDomain {
static constexpr uint64_t Spelling = ((uint64_t)0x1) << 13;
static constexpr uint64_t Viewport = ((uint64_t)0x1) << 14;
static constexpr uint64_t ARIA = ((uint64_t)0x1) << 15;
static constexpr uint64_t Relations = ((uint64_t)0x1) << 16;
static constexpr uint64_t All = ~((uint64_t)0x0);
};
@ -43,6 +46,28 @@ enum class CacheUpdateType {
Update,
};
struct RelationData {
nsStaticAtom* const mAtom;
nsStaticAtom* const mValidTag;
RelationType mType;
};
/**
* This array of RelationData lists our relation types and the cache
* attribute atoms that store their targets. Attributes may describe
* different kinds of relations, depending on the element they originate on.
* For example, an <output> element's `for` attribute describes a CONTROLLER_FOR
* relation, while the `for` attribute of a <label> describes a LABEL_FOR
* relation.
* To ensure we process these attributes appropriately, RelationData.mValidTag
* contains the atom for the tag this attribute/relation type paring is valid
* on. If the pairing is valid for all tag types, this field is null.
*/
static constexpr RelationData kRelationTypeAtoms[] = {
{nsGkAtoms::aria_labelledby, nullptr, RelationType::LABELLED_BY},
{nsGkAtoms::_for, nsGkAtoms::label, RelationType::LABEL_FOR},
};
} // namespace a11y
} // namespace mozilla

View File

@ -87,6 +87,7 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/dom/HTMLBodyElement.h"
#include "mozilla/dom/HTMLLabelElement.h"
#include "mozilla/dom/KeyboardEventBinding.h"
#include "mozilla/dom/TreeWalker.h"
#include "mozilla/dom/UserActivation.h"
@ -1348,6 +1349,10 @@ void LocalAccessible::DOMAttributeChanged(int32_t aNameSpaceID,
}
if (aAttribute == nsGkAtoms::aria_labelledby) {
// We only queue cache updates for explicit relations. Implicit, reverse
// relations are handled in ApplyCache and stored in a map on the remote
// document itself.
mDoc->QueueCacheUpdate(this, CacheDomain::Relations);
mDoc->FireDelayedEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
if (aModType == dom::MutationEvent_Binding::MODIFICATION ||
aModType == dom::MutationEvent_Binding::ADDITION) {
@ -3558,6 +3563,39 @@ already_AddRefed<AccAttributes> LocalAccessible::BundleFieldsForCache(
}
}
if (CacheDomain::Relations) {
for (auto const& data : kRelationTypeAtoms) {
nsTArray<uint64_t> ids;
nsStaticAtom* const relAtom = data.mAtom;
Relation rel;
if (data.mType == RelationType::LABEL_FOR) {
// Labels are a special case -- we need to validate that the target of
// their `for` attribute is in fact labelable. DOM checks this when we
// call GetControl().
if (dom::HTMLLabelElement* labelEl =
dom::HTMLLabelElement::FromNode(mContent)) {
rel.AppendTarget(mDoc, labelEl->GetControl());
}
} else {
// We use an IDRefsIterator here instead of calling RelationByType
// directly because we only want to cache explicit relations. Implicit
// relations will be computed and stored separately in the parent
// process.
rel.AppendIter(new IDRefsIterator(mDoc, mContent, relAtom));
}
while (LocalAccessible* acc = rel.Next()) {
ids.AppendElement(acc->IsDoc() ? 0 : acc->ID());
}
if (ids.Length()) {
fields->SetAttribute(relAtom, std::move(ids));
} else if (aUpdateType == CacheUpdateType::Update) {
fields->SetAttribute(relAtom, DeleteEntry());
}
}
}
if (aUpdateType == CacheUpdateType::Initial) {
// Add fields which never change and thus only need to be included in the
// initial cache push.

View File

@ -66,6 +66,7 @@ void HTMLLabelAccessible::DOMAttributeChanged(int32_t aNameSpaceID,
aModType, aOldValue, aOldState);
if (aAttribute == nsGkAtoms::_for) {
mDoc->QueueCacheUpdate(this, CacheDomain::Relations);
SendCache(CacheDomain::Actions, CacheUpdateType::Update);
}
}