michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: let Ci = Components.interfaces; michael@0: let Cu = Components.utils; michael@0: michael@0: Cu.import('resource://gre/modules/XPCOMUtils.jsm'); michael@0: XPCOMUtils.defineLazyModuleGetter(this, 'Logger', michael@0: 'resource://gre/modules/accessibility/Utils.jsm'); michael@0: XPCOMUtils.defineLazyModuleGetter(this, 'Presentation', michael@0: 'resource://gre/modules/accessibility/Presentation.jsm'); michael@0: XPCOMUtils.defineLazyModuleGetter(this, 'TraversalRules', michael@0: 'resource://gre/modules/accessibility/TraversalRules.jsm'); michael@0: XPCOMUtils.defineLazyModuleGetter(this, 'Utils', michael@0: 'resource://gre/modules/accessibility/Utils.jsm'); michael@0: XPCOMUtils.defineLazyModuleGetter(this, 'EventManager', michael@0: 'resource://gre/modules/accessibility/EventManager.jsm'); michael@0: XPCOMUtils.defineLazyModuleGetter(this, 'ContentControl', michael@0: 'resource://gre/modules/accessibility/ContentControl.jsm'); michael@0: XPCOMUtils.defineLazyModuleGetter(this, 'Roles', michael@0: 'resource://gre/modules/accessibility/Constants.jsm'); michael@0: michael@0: Logger.debug('content-script.js'); michael@0: michael@0: let eventManager = null; michael@0: let contentControl = null; michael@0: michael@0: function forwardToParent(aMessage) { michael@0: // XXX: This is a silly way to make a deep copy michael@0: let newJSON = JSON.parse(JSON.stringify(aMessage.json)); michael@0: newJSON.origin = 'child'; michael@0: sendAsyncMessage(aMessage.name, newJSON); michael@0: } michael@0: michael@0: function forwardToChild(aMessage, aListener, aVCPosition) { michael@0: let acc = aVCPosition || Utils.getVirtualCursor(content.document).position; michael@0: michael@0: if (!Utils.isAliveAndVisible(acc) || acc.role != Roles.INTERNAL_FRAME) { michael@0: return false; michael@0: } michael@0: michael@0: Logger.debug(() => { michael@0: return ['forwardToChild', Logger.accessibleToString(acc), michael@0: aMessage.name, JSON.stringify(aMessage.json, null, ' ')]; michael@0: }); michael@0: michael@0: let mm = Utils.getMessageManager(acc.DOMNode); michael@0: michael@0: if (aListener) { michael@0: mm.addMessageListener(aMessage.name, aListener); michael@0: } michael@0: michael@0: // XXX: This is a silly way to make a deep copy michael@0: let newJSON = JSON.parse(JSON.stringify(aMessage.json)); michael@0: newJSON.origin = 'parent'; michael@0: if (Utils.isContentProcess) { michael@0: // XXX: OOP content's screen offset is 0, michael@0: // so we remove the real screen offset here. michael@0: newJSON.x -= content.mozInnerScreenX; michael@0: newJSON.y -= content.mozInnerScreenY; michael@0: } michael@0: mm.sendAsyncMessage(aMessage.name, newJSON); michael@0: return true; michael@0: } michael@0: michael@0: function activateContextMenu(aMessage) { michael@0: function sendContextMenuCoordinates(aAccessible) { michael@0: let bounds = Utils.getBounds(aAccessible); michael@0: sendAsyncMessage('AccessFu:ActivateContextMenu', {bounds: bounds}); michael@0: } michael@0: michael@0: let position = Utils.getVirtualCursor(content.document).position; michael@0: if (!forwardToChild(aMessage, activateContextMenu, position)) { michael@0: sendContextMenuCoordinates(position); michael@0: } michael@0: } michael@0: michael@0: function presentCaretChange(aText, aOldOffset, aNewOffset) { michael@0: if (aOldOffset !== aNewOffset) { michael@0: let msg = Presentation.textSelectionChanged(aText, aNewOffset, aNewOffset, michael@0: aOldOffset, aOldOffset, true); michael@0: sendAsyncMessage('AccessFu:Present', msg); michael@0: } michael@0: } michael@0: michael@0: function scroll(aMessage) { michael@0: function sendScrollCoordinates(aAccessible) { michael@0: let bounds = Utils.getBounds(aAccessible); michael@0: sendAsyncMessage('AccessFu:DoScroll', michael@0: { bounds: bounds, michael@0: page: aMessage.json.page, michael@0: horizontal: aMessage.json.horizontal }); michael@0: } michael@0: michael@0: let position = Utils.getVirtualCursor(content.document).position; michael@0: if (!forwardToChild(aMessage, scroll, position)) { michael@0: sendScrollCoordinates(position); michael@0: } michael@0: } michael@0: michael@0: function adjustRange(aMessage) { michael@0: function sendUpDownKey(aAccessible) { michael@0: let acc = Utils.getEmbeddedControl(aAccessible) || aAccessible; michael@0: let elem = acc.DOMNode; michael@0: if (elem) { michael@0: if (elem.tagName === 'INPUT' && elem.type === 'range') { michael@0: elem[aMessage.json.direction === 'forward' ? 'stepDown' : 'stepUp'](); michael@0: let changeEvent = content.document.createEvent('UIEvent'); michael@0: changeEvent.initEvent('change', true, true); michael@0: elem.dispatchEvent(changeEvent); michael@0: } else { michael@0: let evt = content.document.createEvent('KeyboardEvent'); michael@0: let keycode = aMessage.json.direction == 'forward' ? michael@0: content.KeyEvent.DOM_VK_DOWN : content.KeyEvent.DOM_VK_UP; michael@0: evt.initKeyEvent( michael@0: "keypress", false, true, null, false, false, false, false, keycode, 0); michael@0: elem.dispatchEvent(evt); michael@0: } michael@0: } michael@0: } michael@0: michael@0: let position = Utils.getVirtualCursor(content.document).position; michael@0: if (!forwardToChild(aMessage, adjustRange, position)) { michael@0: sendUpDownKey(position); michael@0: } michael@0: } michael@0: addMessageListener( michael@0: 'AccessFu:Start', michael@0: function(m) { michael@0: if (m.json.logLevel) { michael@0: Logger.logLevel = Logger[m.json.logLevel]; michael@0: } michael@0: michael@0: Logger.debug('AccessFu:Start'); michael@0: if (m.json.buildApp) michael@0: Utils.MozBuildApp = m.json.buildApp; michael@0: michael@0: addMessageListener('AccessFu:ContextMenu', activateContextMenu); michael@0: addMessageListener('AccessFu:Scroll', scroll); michael@0: addMessageListener('AccessFu:AdjustRange', adjustRange); michael@0: michael@0: if (!eventManager) { michael@0: eventManager = new EventManager(this); michael@0: } michael@0: eventManager.start(); michael@0: michael@0: if (!contentControl) { michael@0: contentControl = new ContentControl(this); michael@0: } michael@0: contentControl.start(); michael@0: michael@0: sendAsyncMessage('AccessFu:ContentStarted'); michael@0: }); michael@0: michael@0: addMessageListener( michael@0: 'AccessFu:Stop', michael@0: function(m) { michael@0: Logger.debug('AccessFu:Stop'); michael@0: michael@0: removeMessageListener('AccessFu:ContextMenu', activateContextMenu); michael@0: removeMessageListener('AccessFu:Scroll', scroll); michael@0: michael@0: eventManager.stop(); michael@0: contentControl.stop(); michael@0: }); michael@0: michael@0: sendAsyncMessage('AccessFu:Ready');