author | Eitan Isaacson <eitan@monotonous.org> |
Fri, 18 May 2012 11:56:38 -0700 | |
changeset 94405 | ae944ea53b59d417e7f2b11a7514c2b1d7eaa46b |
parent 94404 | 87e6d47a1657f53b0386a8bbbd9542b3bf8e00a6 |
child 94406 | aef74c3cd5a1a9dcba989e950210b0952ca6d215 |
push id | 9592 |
push user | eisaacson@mozilla.com |
push date | Fri, 18 May 2012 18:56:47 +0000 |
treeherder | mozilla-inbound@aef74c3cd5a1 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | davidb |
bugs | 756287 |
milestone | 15.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
accessible/src/jsat/AccessFu.jsm | file | annotate | diff | comparison | revisions | |
accessible/src/jsat/Presenters.jsm | file | annotate | diff | comparison | revisions |
--- a/accessible/src/jsat/AccessFu.jsm +++ b/accessible/src/jsat/AccessFu.jsm @@ -210,22 +210,20 @@ var AccessFu = { // focus. let sel = doc.getSelection(); sel.collapse(position.DOMNode, 0); Cc["@mozilla.org/focus-manager;1"] .getService(Ci.nsIFocusManager).moveFocus( doc.defaultView, null, Ci.nsIFocusManager.MOVEFOCUS_CARET, 0); } - let newContext = this.getNewContext(event.oldAccessible, - pivot.position); + let presenterContext = new PresenterContext(pivot.position, + event.oldAccessible); this.presenters.forEach( - function(p) { - p.pivotChanged(pivot.position, newContext); - }); + function(p) { p.pivotChanged(presenterContext); }); break; } case Ci.nsIAccessibleEvent.EVENT_STATE_CHANGE: { let event = aEvent.QueryInterface(Ci.nsIAccessibleStateChangeEvent); if (event.state == Ci.nsIAccessibleStates.STATE_CHECKED && !(event.isExtraState())) { this.presenters.forEach( @@ -308,18 +306,23 @@ var AccessFu = { } ); break; } case Ci.nsIAccessibleEvent.EVENT_FOCUS: { if (this._isBrowserDoc(aEvent.accessible)) { // The document recieved focus, call tabSelected to present current tab. + let docContext = new PresenterContext(aEvent.accessible, null); + let cursorable = aEvent.accessible. + QueryInterface(Ci.nsIAccessibleCursorable); + let vcContext = new PresenterContext( + (cursorable) ? cursorable.virtualCursor.position : null, null); this.presenters.forEach( - function(p) { p.tabSelected(aEvent.accessible); }); + function(p) { p.tabSelected(docContext, vcContext); }); } break; } case Ci.nsIAccessibleEvent.EVENT_TEXT_INSERTED: case Ci.nsIAccessibleEvent.EVENT_TEXT_REMOVED: { if (aEvent.isFromUserInput) { // XXX support live regions as well. @@ -378,51 +381,16 @@ var AccessFu = { _isNotChromeDoc: function _isNotChromeDoc(aDocument) { let location = aDocument.DOMNode.location; if (!location) return false; return location.protocol != "about:"; }, - getNewContext: function getNewContext(aOldObject, aNewObject) { - let newLineage = []; - let oldLineage = []; - - let parent = aNewObject; - while ((parent = parent.parent)) - newLineage.push(parent); - - if (aOldObject) { - parent = aOldObject; - while ((parent = parent.parent)) - oldLineage.push(parent); - } - -// newLineage.reverse(); -// oldLineage.reverse(); - - let i = 0; - let newContext = []; - - while (true) { - let newAncestor = newLineage.pop(); - let oldAncestor = oldLineage.pop(); - - if (newAncestor == undefined) - break; - - if (newAncestor != oldAncestor) - newContext.push(newAncestor); - i++; - } - - return newContext; - }, - // A hash of documents that don't yet have an accessible tree. _pendingDocuments: {}, // So we don't enable/disable twice _enabled: false, // Observing accessibility settings _observingSystemSettings: false
--- a/accessible/src/jsat/Presenters.jsm +++ b/accessible/src/jsat/Presenters.jsm @@ -9,17 +9,18 @@ const Ci = Components.interfaces; const Cu = Components.utils; const Cr = Components.results; Cu.import('resource://gre/modules/accessibility/UtteranceGenerator.jsm'); Cu.import('resource://gre/modules/Services.jsm'); var EXPORTED_SYMBOLS = ['VisualPresenter', 'AndroidPresenter', - 'DummyAndroidPresenter']; + 'DummyAndroidPresenter', + 'PresenterContext']; /** * The interface for all presenter classes. A presenter could be, for example, * a speech output module, or a visual cursor indicator. */ function Presenter() {} Presenter.prototype = { @@ -31,21 +32,20 @@ Presenter.prototype = { /** * Detach function. */ detach: function detach() {}, /** * The virtual cursor's position changed. - * @param {nsIAccessible} aObject the new position. - * @param {nsIAccessible[]} aNewContext the ancestry of the new position that - * is different from the old virtual cursor position. + * @param {PresenterContext} aContext the context object for the new pivot + * position. */ - pivotChanged: function pivotChanged(aObject, aNewContext) {}, + pivotChanged: function pivotChanged(aContext) {}, /** * An object's action has been invoked. * @param {nsIAccessible} aObject the object that has been invoked. * @param {string} aActionName the name of the action. */ actionInvoked: function actionInvoked(aObject, aActionName) {}, @@ -73,21 +73,22 @@ Presenter.prototype = { * state changed, or null if the tab has no associated document yet. * @param {string} aPageState the state name for the tab, valid states are: * 'newtab', 'loading', 'newdoc', 'loaded', 'stopped', and 'reload'. */ tabStateChanged: function tabStateChanged(aDocObj, aPageState) {}, /** * The current tab has changed. - * @param {nsIAccessible} aObject the document contained by the tab - * accessible, or null if it is a new tab with no attached - * document yet. + * @param {PresenterContext} aDocContext context object for tab's + * document. + * @param {PresenterContext} aVCContext context object for tab's current + * virtual cursor position. */ - tabSelected: function tabSelected(aDocObj) {}, + tabSelected: function tabSelected(aDocContext, aVCContext) {}, /** * The viewport has changed, either a scroll, pan, zoom, or * landscape/portrait toggle. */ viewportChanged: function viewportChanged() {} }; @@ -134,44 +135,42 @@ VisualPresenter.prototype = { this.highlightBox = this.stylesheet = null; }, viewportChanged: function VisualPresenter_viewportChanged() { if (this._currentObject) this._highlight(this._currentObject); }, - pivotChanged: function VisualPresenter_pivotChanged(aObject, aNewContext) { - this._currentObject = aObject; + pivotChanged: function VisualPresenter_pivotChanged(aContext) { + this._currentObject = aContext.accessible; - if (!aObject) { + if (!aContext.accessible) { this._hide(); return; } try { - aObject.scrollTo(Ci.nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE); - this._highlight(aObject); + aContext.accessible.scrollTo( + Ci.nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE); + this._highlight(aContext.accessible); } catch (e) { dump('Error getting bounds: ' + e); return; } }, - tabSelected: function VisualPresenter_tabSelected(aDocObj) { - let vcPos = aDocObj ? aDocObj.QueryInterface(Ci.nsIAccessibleCursorable). - virtualCursor.position : null; - - this.pivotChanged(vcPos); + tabSelected: function VisualPresenter_tabSelected(aDocContext, aVCContext) { + this.pivotChanged(aVCContext); }, tabStateChanged: function VisualPresenter_tabStateChanged(aDocObj, aPageState) { if (aPageState == 'newdoc') - this.pivotChanged(null); + this._hide(); }, // Internals _hide: function _hide() { this.highlightBox.style.display = 'none'; }, @@ -229,24 +228,25 @@ AndroidPresenter.prototype = { // Android AccessibilityEvent type constants. ANDROID_VIEW_CLICKED: 0x01, ANDROID_VIEW_LONG_CLICKED: 0x02, ANDROID_VIEW_SELECTED: 0x04, ANDROID_VIEW_FOCUSED: 0x08, ANDROID_VIEW_TEXT_CHANGED: 0x10, ANDROID_WINDOW_STATE_CHANGED: 0x20, - pivotChanged: function AndroidPresenter_pivotChanged(aObject, aNewContext) { + pivotChanged: function AndroidPresenter_pivotChanged(aContext) { let output = []; - for (let i in aNewContext) - output.push.apply(output, - UtteranceGenerator.genForObject(aNewContext[i])); + for (let i in aContext.newAncestry) + output.push.apply( + output, UtteranceGenerator.genForObject(aContext.newAncestry[i])); output.push.apply(output, - UtteranceGenerator.genForObject(aObject, true)); + UtteranceGenerator.genForObject(aContext.accessible, + true)); this.sendMessageToJava({ gecko: { type: 'Accessibility:Event', eventType: this.ANDROID_VIEW_FOCUSED, text: output } }); @@ -257,31 +257,19 @@ AndroidPresenter.prototype = { gecko: { type: 'Accessibility:Event', eventType: this.ANDROID_VIEW_CLICKED, text: UtteranceGenerator.genForAction(aObject, aActionName) } }); }, - tabSelected: function AndroidPresenter_tabSelected(aDocObj) { + tabSelected: function AndroidPresenter_tabSelected(aDocContext, aVCContext) { // Send a pivot change message with the full context utterance for this doc. - let vcDoc = aDocObj.QueryInterface(Ci.nsIAccessibleCursorable); - let context = []; - - let parent = vcDoc.virtualCursor.position || aDocObj; - while ((parent = parent.parent)) { - context.push(parent); - if (parent == aDocObj) - break; - } - - context.reverse(); - - this.pivotChanged(vcDoc.virtualCursor.position || aDocObj, context); + this.pivotChanged(aVCContext); }, tabStateChanged: function AndroidPresenter_tabStateChanged(aDocObj, aPageState) { let stateUtterance = UtteranceGenerator. genForTabStateChange(aDocObj, aPageState); if (!stateUtterance.length) @@ -337,8 +325,67 @@ function DummyAndroidPresenter() {} DummyAndroidPresenter.prototype = { __proto__: AndroidPresenter.prototype, sendMessageToJava: function DummyAndroidPresenter_sendMessageToJava(aMsg) { dump(JSON.stringify(aMsg, null, 2) + '\n'); } }; + +/** + * PresenterContext: An object that generates and caches context information + * for a given accessible and its relationship with another accessible. + */ +function PresenterContext(aAccessible, aOldAccessible) { + this._accessible = aAccessible; + this._oldAccessible = aOldAccessible; +} + +PresenterContext.prototype = { + get accessible() { + return this._accessible; + }, + + get oldAccessible() { + return this._oldAccessible; + }, + + /* + * This is a list of the accessible's ancestry up to the common ancestor + * of the accessible and the old accessible. It is useful for giving the + * user context as to where they are in the heirarchy. + */ + get newAncestry() { + if (!this._newAncestry) { + let newLineage = []; + let oldLineage = []; + + let parent = this._accessible; + while ((parent = parent.parent)) + newLineage.push(parent); + + if (this._oldAccessible) { + parent = this._oldAccessible; + while ((parent = parent.parent)) + oldLineage.push(parent); + } + + let i = 0; + this._newAncestry = []; + + while (true) { + let newAncestor = newLineage.pop(); + let oldAncestor = oldLineage.pop(); + + if (newAncestor == undefined) + break; + + if (newAncestor != oldAncestor) + this._newAncestry.push(newAncestor); + i++; + } + + } + + return this._newAncestry; + } +};