Commit 28df096f authored by dmazzoni's avatar dmazzoni Committed by Commit bot

Fix ChromeVox's detection of whether the current document has focus.

Added a new helper function to determine whether the document has focus,
taking into account whether an iframe or webview element has focus
and whether the document is hidden.

This fixes issues where there were two ChromeVox active indicators showing,
one on the outer frame and one inside the inner frame or webview. It also
fixes issues with other speech-generating events being processed in both
frames at once.

BUG=484904

Review URL: https://codereview.chromium.org/1137403003

Cr-Commit-Position: refs/heads/master@{#329956}
parent 6e57659e
...@@ -474,7 +474,7 @@ cvox.ActiveIndicator.prototype.moveIndicator_ = function( ...@@ -474,7 +474,7 @@ cvox.ActiveIndicator.prototype.moveIndicator_ = function(
var now = new Date().getTime(); var now = new Date().getTime();
var delta = now - this.lastMoveTime_; var delta = now - this.lastMoveTime_;
this.container_.className = 'cvox_indicator_container'; this.container_.className = 'cvox_indicator_container';
if (!document.hasFocus() || this.blurred_) { if (!cvox.ChromeVox.documentHasFocus() || this.blurred_) {
this.container_.classList.add('cvox_indicator_window_not_focused'); this.container_.classList.add('cvox_indicator_window_not_focused');
} }
if (delta > cvox.ActiveIndicator.NORMAL_ANIM_DELAY_MS) { if (delta > cvox.ActiveIndicator.NORMAL_ANIM_DELAY_MS) {
......
...@@ -255,8 +255,14 @@ cvox.ChromeVoxEventWatcher.readFrom = function(store) { ...@@ -255,8 +255,14 @@ cvox.ChromeVoxEventWatcher.readFrom = function(store) {
*/ */
cvox.ChromeVoxEventWatcher.addEvent = function(evt) { cvox.ChromeVoxEventWatcher.addEvent = function(evt) {
// Don't add any events to the events queue if ChromeVox is inactive or the // Don't add any events to the events queue if ChromeVox is inactive or the
// page is hidden. // document isn't focused.
if (!cvox.ChromeVox.isActive || document.webkitHidden) { if (!cvox.ChromeVox.isActive || !cvox.ChromeVox.documentHasFocus()) {
if (evt.type == 'focus') {
// If it's a focus event, update the active indicator so that it
// properly shows and hides as focus moves to iframe and webview
// elements.
cvox.ChromeVox.navigationManager.activeIndicator.syncToNode(evt.target);
}
return; return;
} }
cvox.ChromeVoxEventWatcher.events_.push(evt); cvox.ChromeVoxEventWatcher.events_.push(evt);
...@@ -871,7 +877,7 @@ cvox.ChromeVoxEventWatcher.clipboardEventWatcher = function(evt) { ...@@ -871,7 +877,7 @@ cvox.ChromeVoxEventWatcher.clipboardEventWatcher = function(evt) {
// Don't announce anything unless this document has focus and the // Don't announce anything unless this document has focus and the
// editable element that's the target of the clipboard event is visible. // editable element that's the target of the clipboard event is visible.
var targetNode = /** @type {Node} */(evt.target); var targetNode = /** @type {Node} */(evt.target);
if (!document.hasFocus() || if (!cvox.ChromeVox.documentHasFocus() ||
!targetNode || !targetNode ||
!cvox.DomUtil.isVisible(targetNode) || !cvox.DomUtil.isVisible(targetNode) ||
cvox.AriaUtil.isHidden(targetNode)) { cvox.AriaUtil.isHidden(targetNode)) {
......
...@@ -62,7 +62,8 @@ cvox.InitialSpeech.speak = function() { ...@@ -62,7 +62,8 @@ cvox.InitialSpeech.speak = function() {
// actually happens inside of NavigationManager.reset, which doesn't get // actually happens inside of NavigationManager.reset, which doesn't get
// called until AbstractHost.onPageLoad, but we need to speak and braille the // called until AbstractHost.onPageLoad, but we need to speak and braille the
// initial node here. // initial node here.
if (document.hasFocus() && document.activeElement == document.body) { if (cvox.ChromeVox.documentHasFocus() &&
document.activeElement == document.body) {
cvox.ChromeVox.navigationManager.syncToBeginning(); cvox.ChromeVox.navigationManager.syncToBeginning();
} }
...@@ -74,7 +75,7 @@ cvox.InitialSpeech.speak = function() { ...@@ -74,7 +75,7 @@ cvox.InitialSpeech.speak = function() {
} }
// If this iframe has focus, speak and braille the current focused element. // If this iframe has focus, speak and braille the current focused element.
if (document.hasFocus()) { if (cvox.ChromeVox.documentHasFocus()) {
if (!disableSpeak) { if (!disableSpeak) {
cvox.ChromeVoxEventSuspender.withSuspendedEvents(function() { cvox.ChromeVoxEventSuspender.withSuspendedEvents(function() {
cvox.ChromeVox.navigationManager.finishNavCommand( cvox.ChromeVox.navigationManager.finishNavCommand(
......
...@@ -82,7 +82,7 @@ cvox.LiveRegions.nodesAlreadyHandled = []; ...@@ -82,7 +82,7 @@ cvox.LiveRegions.nodesAlreadyHandled = [];
cvox.LiveRegions.init = function(pageLoadTime, queueMode, disableSpeak) { cvox.LiveRegions.init = function(pageLoadTime, queueMode, disableSpeak) {
cvox.LiveRegions.pageLoadTime = pageLoadTime; cvox.LiveRegions.pageLoadTime = pageLoadTime;
if (disableSpeak || !document.hasFocus()) { if (disableSpeak || !cvox.ChromeVox.documentHasFocus()) {
return false; return false;
} }
...@@ -379,7 +379,7 @@ cvox.LiveRegions.announceChange = function( ...@@ -379,7 +379,7 @@ cvox.LiveRegions.announceChange = function(
cvox.LiveRegions.lastAnnouncedMap[key] = now; cvox.LiveRegions.lastAnnouncedMap[key] = now;
var assertive = cvox.AriaUtil.getAriaLive(liveRoot) == 'assertive'; var assertive = cvox.AriaUtil.getAriaLive(liveRoot) == 'assertive';
if (cvox.Interframe.isIframe() && !document.hasFocus()) { if (cvox.Interframe.isIframe() && !cvox.ChromeVox.documentHasFocus()) {
cvox.Interframe.sendMessageToParentWindow( cvox.Interframe.sendMessageToParentWindow(
{'command': 'speakLiveRegion', {'command': 'speakLiveRegion',
'content': JSON.stringify(navDescriptions), 'content': JSON.stringify(navDescriptions),
......
...@@ -275,3 +275,20 @@ function $(id) { ...@@ -275,3 +275,20 @@ function $(id) {
* @param {Array} tabs * @param {Array} tabs
*/ */
cvox.ChromeVox.injectChromeVoxIntoTabs = function(tabs) {}; cvox.ChromeVox.injectChromeVoxIntoTabs = function(tabs) {};
/**
* Returns whether the document has focus, taking into account whether
* it's hidden and also that if an iframe or webview element has focus,
* the focus is really inside that frame and not in this document.
* @return {boolean} True if the document has focus.
*/
cvox.ChromeVox.documentHasFocus = function() {
if (!document.hasFocus() || document.hidden) {
return false;
}
if (document.activeElement.tagName == 'IFRAME' ||
document.activeElement.tagName == 'WEBVIEW') {
return false;
}
return true;
};
...@@ -49,7 +49,7 @@ cvox.ChromeBraille = function() { ...@@ -49,7 +49,7 @@ cvox.ChromeBraille = function() {
// within the iframe even though the containing document also has focus. // within the iframe even though the containing document also has focus.
// Don't process the event if this document isn't focused or focus lies in // Don't process the event if this document isn't focused or focus lies in
// a descendant. // a descendant.
if (!document.hasFocus() || document.activeElement.tagName == 'IFRAME') { if (!cvox.ChromeVox.documentHasFocus()) {
return; return;
} }
if (msg['message'] == 'BRAILLE' && msg['args']) { if (msg['message'] == 'BRAILLE' && msg['args']) {
......
...@@ -143,7 +143,7 @@ cvox.AbstractHost.prototype.onStateChanged_ = function(state) { ...@@ -143,7 +143,7 @@ cvox.AbstractHost.prototype.onStateChanged_ = function(state) {
cvox.ChromeVox.navigationManager.showOrHideIndicator(true); cvox.ChromeVox.navigationManager.showOrHideIndicator(true);
cvox.ChromeVoxEventWatcher.init(window); cvox.ChromeVoxEventWatcher.init(window);
if (document.activeElement) { if (document.activeElement) {
var speakNodeAlso = document.hasFocus() && !document.webkitHidden; var speakNodeAlso = cvox.ChromeVox.documentHasFocus();
cvox.ApiImplementation.syncToNode( cvox.ApiImplementation.syncToNode(
document.activeElement, speakNodeAlso); document.activeElement, speakNodeAlso);
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment