Bug 1689445 - make accessible retrieval synchronous. r=Jamie

Differential Revision: https://phabricator.services.mozilla.com/D104126
This commit is contained in:
Yura Zenevich 2021-02-05 02:15:18 +00:00
parent 4357fa7621
commit 1a40e8580c
2 changed files with 36 additions and 32 deletions

View File

@ -14,9 +14,6 @@
*/
this.AccessibilityUtils = (function() {
// Duration until the accessible lookup times out.
const GET_ACCESSIBLE_TIMEOUT = 1000;
const FORCE_DISABLE_ACCESSIBILITY_PREF = "accessibility.force_disabled";
// Accessible states.
@ -435,6 +432,32 @@ this.AccessibilityUtils = (function() {
}
}
/**
* Walk node ancestry and force refresh driver tick in every document.
* @param {DOMNode} node
* Node for traversing the ancestry.
*/
function forceRefreshDriverTick(node) {
const wins = [];
let bc = BrowsingContext.getFromWindow(node.ownerDocument.defaultView); // eslint-disable-line
while (bc) {
wins.push(bc.associatedWindow);
bc = bc.embedderWindowGlobal?.browsingContext;
}
let win = wins.pop();
while (win) {
// Stop the refresh driver from doing its regular ticks and force two
// refresh driver ticks: first to let layout update and notify a11y, and
// the second to let a11y process updates.
win.windowUtils.advanceTimeAndRefresh(100);
win.windowUtils.advanceTimeAndRefresh(100);
// Go back to normal refresh driver ticks.
win.windowUtils.restoreNormalRefresh();
win = wins.pop();
}
}
/**
* Get an accessible object for a node.
* Note: this method will not resolve if accessible object does not become
@ -443,10 +466,10 @@ this.AccessibilityUtils = (function() {
* @param {DOMNode} node
* Node to get the accessible object for.
*
* @return {Promise.<nsIAccessible>}
* Promise with an accessibility object for a given node.
* @return {nsIAccessible}
* Accessibility object for a given node.
*/
async function getAccessible(node) {
function getAccessible(node) {
const accessibilityService = Cc[
"@mozilla.org/accessibilityService;1"
].getService(Ci.nsIAccessibilityService);
@ -460,28 +483,9 @@ this.AccessibilityUtils = (function() {
return acc;
}
let resolver, timeoutID;
const accPromise = new Promise(resolve => {
resolver = resolve;
});
const observe = subject => {
acc = accessibilityService.getAccessibleFor(node);
if (acc) {
clearTimeout(timeoutID);
SpecialPowers.Services.obs.removeObserver(observe, "accessible-event");
resolver(acc);
}
};
SpecialPowers.Services.obs.addObserver(observe, "accessible-event");
timeoutID = setTimeout(() => {
// Final attempt in case the show event never fired.
SpecialPowers.Services.obs.removeObserver(observe, "accessible-event");
resolver(accessibilityService.getAccessibleFor(node));
}, GET_ACCESSIBLE_TIMEOUT);
return accPromise;
// Force refresh tick throughout document hierarchy
forceRefreshDriverTick(node);
return accessibilityService.getAccessibleFor(node);
}
function runIfA11YChecks(task) {
@ -498,8 +502,8 @@ this.AccessibilityUtils = (function() {
*
*/
const AccessibilityUtils = {
async assertCanBeClicked(node) {
const acc = await getAccessible(node);
assertCanBeClicked(node) {
const acc = getAccessible(node);
if (!acc) {
if (gEnv.mustHaveAccessibleRule) {
a11yFail("Node is not accessible via accessibility API", {

View File

@ -227,7 +227,7 @@ function computeButtons(aEvent, utils) {
return utils.MOUSE_BUTTONS_NOT_SPECIFIED;
}
async function sendMouseEvent(aEvent, aTarget, aWindow) {
function sendMouseEvent(aEvent, aTarget, aWindow) {
if (
![
"click",
@ -253,7 +253,7 @@ async function sendMouseEvent(aEvent, aTarget, aWindow) {
}
if (aEvent.type === "click" && this.AccessibilityUtils) {
await this.AccessibilityUtils.assertCanBeClicked(aTarget);
this.AccessibilityUtils.assertCanBeClicked(aTarget);
}
var event = aWindow.document.createEvent("MouseEvent");