Bug 963373 - Update cursor after scroll. r=yzen

This commit is contained in:
Eitan Isaacson 2014-01-29 15:08:53 -08:00
parent 5f9cdeea9f
commit 46acb0203b
3 changed files with 86 additions and 58 deletions

View File

@ -57,6 +57,7 @@ this.EventManager.prototype = {
this.webProgress.addProgressListener(this,
(Ci.nsIWebProgress.NOTIFY_STATE_ALL |
Ci.nsIWebProgress.NOTIFY_LOCATION));
this.addEventListener('wheel', this, true);
this.addEventListener('scroll', this, true);
this.addEventListener('resize', this, true);
}
@ -77,6 +78,7 @@ this.EventManager.prototype = {
AccessibilityEventObserver.removeListener(this);
try {
this.webProgress.removeProgressListener(this);
this.removeEventListener('wheel', this, true);
this.removeEventListener('scroll', this, true);
this.removeEventListener('resize', this, true);
} catch (x) {
@ -89,6 +91,23 @@ this.EventManager.prototype = {
handleEvent: function handleEvent(aEvent) {
try {
switch (aEvent.type) {
case 'wheel':
{
let attempts = 0;
let vc = Utils.getVirtualCursor(this.contentScope.content.document);
let intervalId = this.contentScope.content.setInterval(() => {
if (!Utils.isAliveAndVisible(vc.position, true)) {
this.contentScope.content.clearInterval(intervalId);
let delta = aEvent.deltaX || aEvent.deltaY;
this.contentScope.content.setTimeout(() => {
vc[delta > 0 ? 'moveNext' : 'movePrevious'](TraversalRules.SimpleOnScreen);
}, 100);
} else if (++attempts > 5) {
this.contentScope.content.clearInterval(intervalId);
}
}, 150);
break;
}
case 'scroll':
case 'resize':
{

View File

@ -22,13 +22,14 @@ XPCOMUtils.defineLazyModuleGetter(this, 'States',
let gSkipEmptyImages = new PrefCache('accessibility.accessfu.skip_empty_images');
function BaseTraversalRule(aRoles, aMatchFunc) {
function BaseTraversalRule(aRoles, aMatchFunc, aPreFilter) {
this._explicitMatchRoles = new Set(aRoles);
this._matchRoles = aRoles;
if (aRoles.indexOf(Roles.LABEL) < 0) {
this._matchRoles.push(Roles.LABEL);
}
this._matchFunc = aMatchFunc || function (acc) { return Filters.MATCH; };
this.preFilter = aPreFilter || gSimplePreFilter;
}
BaseTraversalRule.prototype = {
@ -37,11 +38,6 @@ BaseTraversalRule.prototype = {
return aRules.value.length;
},
preFilter: Ci.nsIAccessibleTraversalRule.PREFILTER_DEFUNCT |
Ci.nsIAccessibleTraversalRule.PREFILTER_INVISIBLE |
Ci.nsIAccessibleTraversalRule.PREFILTER_ARIA_HIDDEN |
Ci.nsIAccessibleTraversalRule.PREFILTER_TRANSPARENT,
match: function BaseTraversalRule_match(aAccessible)
{
let role = aAccessible.role;
@ -96,59 +92,71 @@ var gSimpleTraversalRoles =
// Used for traversing in to child OOP frames.
Roles.INTERNAL_FRAME];
this.TraversalRules = {
Simple: new BaseTraversalRule(
gSimpleTraversalRoles,
function Simple_match(aAccessible) {
function hasZeroOrSingleChildDescendants () {
for (let acc = aAccessible; acc.childCount > 0; acc = acc.firstChild) {
if (acc.childCount > 1) {
return false;
}
}
return true;
}
switch (aAccessible.role) {
case Roles.COMBOBOX:
// We don't want to ignore the subtree because this is often
// where the list box hangs out.
return Filters.MATCH;
case Roles.TEXT_LEAF:
{
// Nameless text leaves are boring, skip them.
let name = aAccessible.name;
if (name && name.trim())
return Filters.MATCH;
else
return Filters.IGNORE;
}
case Roles.STATICTEXT:
{
let parent = aAccessible.parent;
// Ignore prefix static text in list items. They are typically bullets or numbers.
if (parent.childCount > 1 && aAccessible.indexInParent == 0 &&
parent.role == Roles.LISTITEM)
return Filters.IGNORE;
return Filters.MATCH;
}
case Roles.GRAPHIC:
return TraversalRules._shouldSkipImage(aAccessible);
case Roles.LINK:
case Roles.HEADER:
case Roles.HEADING:
return hasZeroOrSingleChildDescendants() ?
(Filters.MATCH | Filters.IGNORE_SUBTREE) : (Filters.IGNORE);
default:
// Ignore the subtree, if there is one. So that we don't land on
// the same content that was already presented by its parent.
return Filters.MATCH |
Filters.IGNORE_SUBTREE;
var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) {
function hasZeroOrSingleChildDescendants () {
for (let acc = aAccessible; acc.childCount > 0; acc = acc.firstChild) {
if (acc.childCount > 1) {
return false;
}
}
),
return true;
}
switch (aAccessible.role) {
case Roles.COMBOBOX:
// We don't want to ignore the subtree because this is often
// where the list box hangs out.
return Filters.MATCH;
case Roles.TEXT_LEAF:
{
// Nameless text leaves are boring, skip them.
let name = aAccessible.name;
if (name && name.trim())
return Filters.MATCH;
else
return Filters.IGNORE;
}
case Roles.STATICTEXT:
{
let parent = aAccessible.parent;
// Ignore prefix static text in list items. They are typically bullets or numbers.
if (parent.childCount > 1 && aAccessible.indexInParent == 0 &&
parent.role == Roles.LISTITEM)
return Filters.IGNORE;
return Filters.MATCH;
}
case Roles.GRAPHIC:
return TraversalRules._shouldSkipImage(aAccessible);
case Roles.LINK:
case Roles.HEADER:
case Roles.HEADING:
return hasZeroOrSingleChildDescendants() ?
(Filters.MATCH | Filters.IGNORE_SUBTREE) : (Filters.IGNORE);
default:
// Ignore the subtree, if there is one. So that we don't land on
// the same content that was already presented by its parent.
return Filters.MATCH |
Filters.IGNORE_SUBTREE;
}
};
var gSimplePreFilter = Ci.nsIAccessibleTraversalRule.PREFILTER_DEFUNCT |
Ci.nsIAccessibleTraversalRule.PREFILTER_INVISIBLE |
Ci.nsIAccessibleTraversalRule.PREFILTER_ARIA_HIDDEN |
Ci.nsIAccessibleTraversalRule.PREFILTER_TRANSPARENT;
this.TraversalRules = {
Simple: new BaseTraversalRule(gSimpleTraversalRoles, gSimpleMatchFunc),
SimpleOnScreen: new BaseTraversalRule(
gSimpleTraversalRoles, gSimpleMatchFunc,
Ci.nsIAccessibleTraversalRule.PREFILTER_DEFUNCT |
Ci.nsIAccessibleTraversalRule.PREFILTER_INVISIBLE |
Ci.nsIAccessibleTraversalRule.PREFILTER_ARIA_HIDDEN |
Ci.nsIAccessibleTraversalRule.PREFILTER_TRANSPARENT |
Ci.nsIAccessibleTraversalRule.PREFILTER_OFFSCREEN),
Anchor: new BaseTraversalRule(
[Roles.LINK],

View File

@ -269,7 +269,7 @@ this.Utils = {
return false;
},
isAliveAndVisible: function isAliveAndVisible(aAccessible) {
isAliveAndVisible: function isAliveAndVisible(aAccessible, aIsOnScreen) {
if (!aAccessible) {
return false;
}
@ -277,6 +277,7 @@ this.Utils = {
try {
let state = this.getState(aAccessible);
if (state.contains(States.DEFUNCT) || state.contains(States.INVISIBLE) ||
(aIsOnScreen && state.contains(States.OFFSCREEN)) ||
Utils.inHiddenSubtree(aAccessible)) {
return false;
}