diff --git a/accessible/src/jsat/AccessFu.jsm b/accessible/src/jsat/AccessFu.jsm index 10f740af2de2..78722140a950 100644 --- a/accessible/src/jsat/AccessFu.jsm +++ b/accessible/src/jsat/AccessFu.jsm @@ -356,7 +356,56 @@ this.AccessFu = { // Keep track of message managers tha already have a 'content-script.js' // injected. - _processedMessageManagers: [] + _processedMessageManagers: [], + + /** + * Adjusts the given bounds relative to the given browser. Converts from screen + * or device pixels to either device or CSS pixels. + * @param {Rect} aJsonBounds the bounds to adjust + * @param {browser} aBrowser the browser we want the bounds relative to + * @param {bool} aToCSSPixels whether to convert to CSS pixels (as opposed to + * device pixels) + * @param {bool} aFromDevicePixels whether to convert from device pixels (as + * opposed to screen pixels) + */ + adjustContentBounds: function(aJsonBounds, aBrowser, aToCSSPixels, aFromDevicePixels) { + let bounds = new Rect(aJsonBounds.left, aJsonBounds.top, + aJsonBounds.right - aJsonBounds.left, + aJsonBounds.bottom - aJsonBounds.top); + let win = Utils.win; + let dpr = win.devicePixelRatio; + let vp = Utils.getViewport(win); + let offset = { left: -win.mozInnerScreenX, top: -win.mozInnerScreenY }; + + if (!aBrowser.contentWindow) { + // OOP browser, add offset of browser. + // The offset of the browser element in relation to its parent window. + let clientRect = aBrowser.getBoundingClientRect(); + let win = aBrowser.ownerDocument.defaultView; + offset.left += clientRect.left + win.mozInnerScreenX; + offset.top += clientRect.top + win.mozInnerScreenY; + } + + // Here we scale from screen pixels to layout device pixels by dividing by + // the resolution (caused by pinch-zooming). The resolution is the viewport + // zoom divided by the devicePixelRatio. If there's no viewport, then we're + // on a platform without pinch-zooming and we can just ignore this. + if (!aFromDevicePixels && vp) { + bounds = bounds.scale(vp.zoom / dpr, vp.zoom / dpr); + } + + // Add the offset; the offset is in CSS pixels, so multiply the + // devicePixelRatio back in before adding to preserve unit consistency. + bounds = bounds.translate(offset.left * dpr, offset.top * dpr); + + // If we want to get to CSS pixels from device pixels, this needs to be + // further divided by the devicePixelRatio due to widget scaling. + if (aToCSSPixels) { + bounds = bounds.scale(1 / dpr, 1 / dpr); + } + + return bounds.expandToIntegers(); + } }; var Output = { @@ -472,7 +521,7 @@ var Output = { } let padding = aDetails.padding; - let r = this._adjustBounds(aDetails.bounds, aBrowser); + let r = AccessFu.adjustContentBounds(aDetails.bounds, aBrowser, true); // First hide it to avoid flickering when changing the style. highlightBox.style.display = 'none'; @@ -536,7 +585,7 @@ var Output = { for each (let androidEvent in aDetails) { androidEvent.type = 'Accessibility:Event'; if (androidEvent.bounds) - androidEvent.bounds = this._adjustBounds(androidEvent.bounds, aBrowser, true); + androidEvent.bounds = AccessFu.adjustContentBounds(androidEvent.bounds, aBrowser); switch(androidEvent.eventType) { case ANDROID_VIEW_TEXT_CHANGED: @@ -559,33 +608,6 @@ var Output = { Braille: function Braille(aDetails, aBrowser) { Logger.debug('Braille output: ' + aDetails.text); - }, - - _adjustBounds: function(aJsonBounds, aBrowser, aIncludeZoom) { - let bounds = new Rect(aJsonBounds.left, aJsonBounds.top, - aJsonBounds.right - aJsonBounds.left, - aJsonBounds.bottom - aJsonBounds.top); - let vp = Utils.getViewport(Utils.win) || { zoom: 1.0, offsetY: 0 }; - let root = Utils.win; - let offset = { left: -root.mozInnerScreenX, top: -root.mozInnerScreenY }; - let scale = 1 / Utils.getPixelsPerCSSPixel(Utils.win); - - if (!aBrowser.contentWindow) { - // OOP browser, add offset of browser. - // The offset of the browser element in relation to its parent window. - let clientRect = aBrowser.getBoundingClientRect(); - let win = aBrowser.ownerDocument.defaultView; - offset.left += clientRect.left + win.mozInnerScreenX; - offset.top += clientRect.top + win.mozInnerScreenY; - } - - let newBounds = bounds.scale(scale, scale).translate(offset.left, offset.top); - - if (aIncludeZoom) { - newBounds = newBounds.scale(vp.zoom, vp.zoom); - } - - return newBounds.expandToIntegers(); } }; @@ -615,9 +637,6 @@ var Input = { this._handleKeypress(aEvent); break; case 'mozAccessFuGesture': - let vp = Utils.getViewport(Utils.win) || { zoom: 1.0 }; - aEvent.detail.x *= vp.zoom; - aEvent.detail.y *= vp.zoom; this._handleGesture(aEvent.detail); break; } @@ -796,10 +815,10 @@ var Input = { activateContextMenu: function activateContextMenu(aMessage) { if (Utils.MozBuildApp === 'mobile/android') { - let vp = Utils.getViewport(Utils.win) || { zoom: 1.0 }; + let p = AccessFu.adjustContentBounds(aMessage.bounds, Utils.CurrentBrowser, + true, true).center(); Services.obs.notifyObservers(null, 'Gesture:LongPress', - JSON.stringify({x: aMessage.x / vp.zoom, - y: aMessage.y / vp.zoom})); + JSON.stringify({x: p.x, y: p.y})); } }, diff --git a/accessible/src/jsat/TouchAdapter.jsm b/accessible/src/jsat/TouchAdapter.jsm index dfd287514308..7edd6099ca2c 100644 --- a/accessible/src/jsat/TouchAdapter.jsm +++ b/accessible/src/jsat/TouchAdapter.jsm @@ -326,8 +326,8 @@ this.TouchAdapter = { * of one single touch. */ function TouchPoint(aTouch, aTime, aDPI) { - this.startX = this.x = aTouch.screenX; - this.startY = this.y = aTouch.screenY; + this.startX = this.x = aTouch.screenX * this.scaleFactor; + this.startY = this.y = aTouch.screenY * this.scaleFactor; this.startTime = aTime; this.distanceTraveled = 0; this.dpi = aDPI; @@ -338,8 +338,8 @@ TouchPoint.prototype = { update: function TouchPoint_update(aTouch, aTime) { let lastX = this.x; let lastY = this.y; - this.x = aTouch.screenX; - this.y = aTouch.screenY; + this.x = aTouch.screenX * this.scaleFactor; + this.y = aTouch.screenY * this.scaleFactor; this.time = aTime; this.distanceTraveled += this.getDistanceToCoord(lastX, lastY); @@ -349,6 +349,20 @@ TouchPoint.prototype = { return Math.sqrt(Math.pow(this.x - aX, 2) + Math.pow(this.y - aY, 2)); }, + get scaleFactor() { + if (!this._scaleFactor) { + // Android events come with the x, y coordinates affected by the widget + // scaling; we restore it to normal here. + if (Utils.MozBuildApp == 'mobile/android') { + this._scaleFactor = Utils.win.devicePixelRatio; + } else { + this._scaleFactor = 1; + } + } + + return this._scaleFactor; + }, + finish: function TouchPoint_finish() { this.done = true; }, diff --git a/accessible/src/jsat/Utils.jsm b/accessible/src/jsat/Utils.jsm index b9a924963dbe..4055650825b2 100644 --- a/accessible/src/jsat/Utils.jsm +++ b/accessible/src/jsat/Utils.jsm @@ -221,11 +221,6 @@ this.Utils = { return doc.QueryInterface(Ci.nsIAccessibleDocument).virtualCursor; }, - getPixelsPerCSSPixel: function getPixelsPerCSSPixel(aWindow) { - return aWindow.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils).screenPixelsPerCSSPixel; - }, - getBounds: function getBounds(aAccessible) { let objX = {}, objY = {}, objW = {}, objH = {}; aAccessible.getBounds(objX, objY, objW, objH); @@ -684,4 +679,4 @@ PrefCache.prototype = { QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]) -}; \ No newline at end of file +}; diff --git a/accessible/src/jsat/content-script.js b/accessible/src/jsat/content-script.js index 7e0c02662a02..f02759b60581 100644 --- a/accessible/src/jsat/content-script.js +++ b/accessible/src/jsat/content-script.js @@ -97,10 +97,8 @@ function moveToPoint(aMessage) { let rule = TraversalRules[details.rule]; try { - if (!this._ppcp) { - this._ppcp = Utils.getPixelsPerCSSPixel(content); - } - vc.moveToPoint(rule, details.x * this._ppcp, details.y * this._ppcp, true); + let dpr = content.devicePixelRatio; + vc.moveToPoint(rule, details.x * dpr, details.y * dpr, true); forwardToChild(aMessage, moveToPoint, vc.position); } catch (x) { Logger.logException(x, 'Failed move to point'); @@ -219,9 +217,7 @@ function activateCurrent(aMessage) { function activateContextMenu(aMessage) { function sendContextMenuCoordinates(aAccessible) { let bounds = Utils.getBounds(aAccessible); - sendAsyncMessage('AccessFu:ActivateContextMenu', - { x: bounds.left + bounds.width / 2, - y: bounds.top + bounds.height / 2 }); + sendAsyncMessage('AccessFu:ActivateContextMenu', {bounds: bounds}); } let position = Utils.getVirtualCursor(content.document).position;