From 9e78018010e29956dc02520d1b8cae30594d3e78 Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Thu, 19 Aug 2021 07:51:28 +0000 Subject: [PATCH] Bug 1725540 - Use nsIDOMWindowUtils.toScreenRect to get positions in the screen coords to avoid accessing window.top directly. r=tnikkel Differential Revision: https://phabricator.services.mozilla.com/D122560 --- .../mochitest/apz_test_native_event_utils.js | 91 ++++++++++++------- gfx/layers/apz/test/mochitest/mochitest.ini | 9 +- 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js b/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js index cd246039ba5a..f27d7cbf0e71 100644 --- a/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js +++ b/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js @@ -193,7 +193,7 @@ function getBoundingClientRectRelativeToVisualViewport(aElement) { // |aTarget| may be an element (contained in the root content document or // a subdocument) or, as a special case, the root content window. // FIXME: Support iframe windows as targets. -function getTargetRect(aTarget) { +function _getTargetRect(aTarget) { let rect = { left: 0, top: 0, width: 0, height: 0 }; // If the target is the root content window, its origin relative @@ -258,19 +258,18 @@ function getTargetRect(aTarget) { aTarget = iframe; } - // Now we have coordinates relative to the root content document's - // layout viewport. Subtract the offset of the visual viewport - // relative to the layout viewport, to get coordinates relative to - // the visual viewport. - var offsetX = {}, - offsetY = {}; - let rootUtils = SpecialPowers.getDOMWindowUtils(window.top); - rootUtils.getVisualViewportOffsetRelativeToLayoutViewport(offsetX, offsetY); - rect.left -= offsetX.value; - rect.top -= offsetY.value; return rect; } +// Returns the in-process root window for the given |aWindow|. +function getInProcessRootWindow(aWindow) { + let window = aWindow; + while (window.frameElement) { + window = window.frameElement.ownerDocument.defaultView; + } + return window; +} + // Convert (offsetX, offsetY) of target or center of it, in CSS pixels to device // pixels relative to the screen. // TODO: this function currently does not incorporate some CSS transforms on @@ -290,31 +289,53 @@ async function coordinatesRelativeToScreen(aParams) { // harness. // 2. The mochitest itself creates an iframe and calls this function from // script running in the context of the iframe. - // Since the resolution applies to the root content document, below we use - // the mozInnerScreen{X,Y} of the root content window (window.top) only, - // and factor any offsets between iframe windows and the root content window - // into |origin|. - const utils = SpecialPowers.getDOMWindowUtils(window); - const deviceScale = utils.screenPixelsPerCSSPixel; - const deviceScaleNoOverride = utils.screenPixelsPerCSSPixelNoOverride; - const resolution = await getResolution(); - const rect = getTargetRect(target); - // moxInnerScreen{X,Y} are in CSS coordinates of the browser chrome. - // The device scale applies to them, but the resolution only zooms the content. - // In addition, if we're inside RDM, RDM overrides the device scale; - // the overridden scale only applies to the content inside the RDM - // document, not to mozInnerScreen{X,Y}. + // Since the resolution applies to the top level content document, below we + // use the mozInnerScreen{X,Y} of the top level content window (window.top) + // only for the case where this function gets called in the top level content + // document. In other cases we use nsIDOMWindowUtils.toScreenRect(). + + // We do often specify `window` as the target, if it's the top level window, + // `nsIDOMWindowUtils.toScreenRect` isn't suitable because the function is + // supposed to be called with values in the document coords, so for example + // if desktop zoom is being applied, (0, 0) in the document coords might be + // outside of the visual viewport, i.e. it's going to be negative with the + // `toScreenRect` conversion, whereas the call sites with `window` of this + // function expect (0, 0) position should be the visual viport's offset. So + // in such cases we simply use mozInnerScreen{X,Y} to convert the given value + // to the screen coords. + if (target instanceof Window && window.parent == window) { + // moxInnerScreen{X,Y} are in CSS coordinates of the browser chrome. + // The device scale applies to them, but the resolution only zooms the content. + // In addition, if we're inside RDM, RDM overrides the device scale; + // the overridden scale only applies to the content inside the RDM + // document, not to mozInnerScreen{X,Y}. + const utils = SpecialPowers.getDOMWindowUtils(window); + const resolution = await getResolution(); + const deviceScale = utils.screenPixelsPerCSSPixel; + const deviceScaleNoOverride = utils.screenPixelsPerCSSPixelNoOverride; + return { + x: + window.mozInnerScreenX * deviceScaleNoOverride + + (atCenter ? 0 : offsetX) * resolution * deviceScale, + y: + window.mozInnerScreenY * deviceScaleNoOverride + + (atCenter ? 0 : offsetY) * resolution * deviceScale, + }; + } + + const rect = _getTargetRect(target); + + const utils = SpecialPowers.getDOMWindowUtils(getInProcessRootWindow(window)); + const positionInScreenCoords = utils.toScreenRect( + rect.left + (atCenter ? rect.width / 2 : offsetX), + rect.top + (atCenter ? rect.height / 2 : offsetY), + 0, + 0 + ); + return { - x: - window.top.mozInnerScreenX * deviceScaleNoOverride + - (rect.left + (atCenter ? rect.width / 2 : offsetX)) * - resolution * - deviceScale, - y: - window.top.mozInnerScreenY * deviceScaleNoOverride + - (rect.top + (atCenter ? rect.height / 2 : offsetY)) * - resolution * - deviceScale, + x: positionInScreenCoords.x, + y: positionInScreenCoords.y, }; } diff --git a/gfx/layers/apz/test/mochitest/mochitest.ini b/gfx/layers/apz/test/mochitest/mochitest.ini index ef7e659cb765..cd1f46beb72d 100644 --- a/gfx/layers/apz/test/mochitest/mochitest.ini +++ b/gfx/layers/apz/test/mochitest/mochitest.ini @@ -14,16 +14,13 @@ [test_bug1151667.html] skip-if = os == 'android' # wheel events not supported on mobile - xorigin # JavaScript error: , line 0: uncaught exception: Object [test_bug1253683.html] skip-if = os == 'android' # wheel events not supported on mobile verify && debug && os == 'linux' - xorigin # JavaScript error: , line 0: uncaught exception: Object [test_bug1277814.html] skip-if = os == 'android' # wheel events not supported on mobile - xorigin # JavaScript error: , line 0: uncaught exception: Object [test_bug1304689.html] [test_bug1304689-2.html] [test_group_bug1464568.html] @@ -67,11 +64,10 @@ skip-if = os == 'android' # wheel events not supported on mobile os == 'linux' && fission && headless # Bug 1722907 - xorigin # JavaScript error: , line 0: uncaught exception: Object + xorigin # "scrolling 'inner2' should cause it to be directly activated" etc. [test_relative_update.html] skip-if = os == 'android' # wheel events not supported on mobile - xorigin # JavaScript error: , line 0: uncaught exception: Object [test_scroll_inactive_bug1190112.html] skip-if = (os == 'android') # wheel events not supported on mobile [test_scroll_inactive_flattened_frame.html] @@ -82,15 +78,12 @@ skip-if = toolkit == 'android' # wheel events not supported on mobile toolkit == 'cocoa' # synthesized wheel smooth-scrolling not supported on OS X - xorigin # JavaScript error: , line 0: uncaught exception: Object [test_wheel_scroll.html] skip-if = os == 'android' # wheel events not supported on mobile - xorigin # JavaScript error: , line 0: uncaught exception: Object [test_wheel_transactions.html] skip-if = toolkit == 'android' # wheel events not supported on mobile - xorigin # JavaScript error: , line 0: uncaught exception: Object [test_group_overrides.html] skip-if = toolkit == 'android' # wheel events not supported on mobile