зеркало из https://github.com/mozilla/gecko-dev.git
Bug 493683 part 2: When an Accessible mutates, fire name change events on an Accessible labelled by it (or an ancestor thereof) via a relation. r=eeejay
HasNameDependent is now set on an Accessible (and thus its descendants) which has A LABEL_FOR relation. When text mutations occur on such an Accessible, EventQueue::PushNameChange now queues a name change for the Accessible being labelled. Differential Revision: https://phabricator.services.mozilla.com/D102677
This commit is contained in:
Родитель
1af2138c00
Коммит
77fe9db976
|
@ -14,6 +14,7 @@
|
|||
#ifdef A11Y_LOG
|
||||
# include "Logging.h"
|
||||
#endif
|
||||
#include "Relation.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
@ -48,31 +49,41 @@ bool EventQueue::PushEvent(AccEvent* aEvent) {
|
|||
}
|
||||
|
||||
bool EventQueue::PushNameChange(Accessible* aTarget) {
|
||||
// Fire name change event on parent given that this event hasn't been
|
||||
// coalesced, the parent's name was calculated from its subtree, and the
|
||||
// subtree was changed.
|
||||
// Fire name change event on parent or related Accessible being labelled given
|
||||
// that this event hasn't been coalesced, the dependent's name was calculated
|
||||
// from this subtree, and the subtree was changed.
|
||||
bool pushed = false;
|
||||
bool checkAncestor = true;
|
||||
if (aTarget->HasNameDependent()) {
|
||||
// Only continue traversing up the tree if it's possible that the parent
|
||||
// accessible's name can depend on this accessible's name.
|
||||
// Accessible's name (or an Accessible being labelled by this Accessible or
|
||||
// an ancestor) can depend on this Accessible's name.
|
||||
Accessible* parent = aTarget->Parent();
|
||||
while (parent &&
|
||||
nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeIfReqRule)) {
|
||||
// Test possible name dependent parent.
|
||||
if (nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeRule)) {
|
||||
if (checkAncestor &&
|
||||
nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeRule)) {
|
||||
nsAutoString name;
|
||||
ENameValueFlag nameFlag = parent->Name(name);
|
||||
// If name is obtained from subtree, fire name change event.
|
||||
if (nameFlag == eNameFromSubtree) {
|
||||
RefPtr<AccEvent> nameChangeEvent =
|
||||
new AccEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, parent);
|
||||
return PushEvent(nameChangeEvent);
|
||||
pushed |= PushEvent(nameChangeEvent);
|
||||
}
|
||||
break;
|
||||
checkAncestor = false;
|
||||
}
|
||||
Relation rel = parent->RelationByType(RelationType::LABEL_FOR);
|
||||
while (Accessible* relTarget = rel.Next()) {
|
||||
RefPtr<AccEvent> nameChangeEvent =
|
||||
new AccEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, relTarget);
|
||||
pushed |= PushEvent(nameChangeEvent);
|
||||
}
|
||||
parent = parent->Parent();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return pushed;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -114,9 +114,8 @@ class NotificationController final : public EventQueue,
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates and adds a name change event into the queue for a container of
|
||||
* the given accessible, if the accessible is a part of name computation of
|
||||
* the container.
|
||||
* Creates and adds a name change event into the queue for an Accessible which
|
||||
* depends on the given Accessible for name computation, if any.
|
||||
*/
|
||||
void QueueNameChange(Accessible* aChangeTarget) {
|
||||
if (PushNameChange(aChangeTarget)) {
|
||||
|
|
|
@ -2069,8 +2069,8 @@ void Accessible::BindToParent(Accessible* aParent, uint32_t aIndexInParent) {
|
|||
mParent = aParent;
|
||||
mIndexInParent = aIndexInParent;
|
||||
|
||||
// Note: this is currently only used for richlistitems and their children.
|
||||
if (mParent->HasNameDependent() || mParent->IsXULListItem()) {
|
||||
if (mParent->HasNameDependent() || mParent->IsXULListItem() ||
|
||||
RelationByType(RelationType::LABEL_FOR).Next()) {
|
||||
mContextFlags |= eHasNameDependent;
|
||||
} else {
|
||||
mContextFlags &= ~eHasNameDependent;
|
||||
|
|
|
@ -19,6 +19,11 @@
|
|||
src="../states.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
let PromEvents = {};
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/a11y/accessible/tests/mochitest/promisified-events.js",
|
||||
PromEvents);
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
// Invokers
|
||||
|
||||
|
@ -57,8 +62,15 @@
|
|||
// gA11yEventDumpToConsole = true; // debuggin
|
||||
|
||||
var gQueue = null;
|
||||
function doTests() {
|
||||
async function doTests() {
|
||||
gQueue = new eventQueue();
|
||||
// Later tests use await.
|
||||
let queueFinished = new Promise(resolve => {
|
||||
gQueue.onFinish = function() {
|
||||
resolve();
|
||||
return DO_NOT_FINISH_TEST;
|
||||
};
|
||||
});
|
||||
|
||||
gQueue.push(new setAttr("tst1", "aria-label", "hi",
|
||||
new invokerChecker(EVENT_NAME_CHANGE, "tst1")));
|
||||
|
@ -88,7 +100,26 @@
|
|||
gQueue.push(new setAttr("tst4", "title", "title",
|
||||
new invokerChecker(EVENT_NAME_CHANGE, "tst4")));
|
||||
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
gQueue.invoke();
|
||||
await queueFinished;
|
||||
// Tests beyond this point use await rather than eventQueue.
|
||||
|
||||
const labelledBy = getNode("labelledBy");
|
||||
const label = getNode("label");
|
||||
let nameChanged = PromEvents.waitForEvent(EVENT_NAME_CHANGE, labelledBy);
|
||||
info("Changing text of aria-labelledby target");
|
||||
label.textContent = "l2";
|
||||
await nameChanged;
|
||||
nameChanged = PromEvents.waitForEvent(EVENT_NAME_CHANGE, labelledBy);
|
||||
info("Adding node to aria-labelledby target");
|
||||
label.innerHTML = '<p id="labelChild">l3</p>';
|
||||
await nameChanged;
|
||||
nameChanged = PromEvents.waitForEvent(EVENT_NAME_CHANGE, labelledBy);
|
||||
info("Changing text of aria-labelledby target's child");
|
||||
getNode("labelChild").textContent = "l4";
|
||||
await nameChanged;
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
@ -114,6 +145,9 @@
|
|||
<img id="tst3">
|
||||
<img id="tst4" src="../moz.png">
|
||||
|
||||
<div id="labelledBy" aria-labelledby="label"></div>
|
||||
<div id="label">l1</div>
|
||||
|
||||
<div id="eventdump"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Загрузка…
Ссылка в новой задаче