Bug 1885106 - Implement LayoutUtils.rectToTopLevelWidgetRect. r=layout-reviewers,emilio
Differential Revision: https://phabricator.services.mozilla.com/D211131
This commit is contained in:
@@ -1856,8 +1856,8 @@ nsDOMWindowUtils::TransformRectLayoutToVisual(float aX, float aY, float aWidth,
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<mozilla::ScreenRect, nsresult> nsDOMWindowUtils::ConvertToScreenRect(
|
Result<mozilla::LayoutDeviceRect, nsresult> nsDOMWindowUtils::ConvertTo(
|
||||||
float aX, float aY, float aWidth, float aHeight) {
|
float aX, float aY, float aWidth, float aHeight, CoordsType aCoordsType) {
|
||||||
nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
|
nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
|
||||||
if (!window) {
|
if (!window) {
|
||||||
return Err(NS_ERROR_NOT_AVAILABLE);
|
return Err(NS_ERROR_NOT_AVAILABLE);
|
||||||
@@ -1894,25 +1894,28 @@ Result<mozilla::ScreenRect, nsresult> nsDOMWindowUtils::ConvertToScreenRect(
|
|||||||
LayoutDeviceRect devPixelsRect = LayoutDeviceRect::FromAppUnits(
|
LayoutDeviceRect devPixelsRect = LayoutDeviceRect::FromAppUnits(
|
||||||
appUnitsRect, presContext->AppUnitsPerDevPixel());
|
appUnitsRect, presContext->AppUnitsPerDevPixel());
|
||||||
devPixelsRect =
|
devPixelsRect =
|
||||||
widget->WidgetToTopLevelWidgetTransform().TransformBounds(devPixelsRect) +
|
widget->WidgetToTopLevelWidgetTransform().TransformBounds(devPixelsRect);
|
||||||
widget->TopLevelWidgetToScreenOffset();
|
|
||||||
|
|
||||||
return ViewAs<ScreenPixel>(
|
switch (aCoordsType) {
|
||||||
devPixelsRect, PixelCastJustification::ScreenIsParentLayerForRoot);
|
case CoordsType::Screen:
|
||||||
|
devPixelsRect += widget->TopLevelWidgetToScreenOffset();
|
||||||
|
break;
|
||||||
|
case CoordsType::TopLevelWidget:
|
||||||
|
// There's nothing to do.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return devPixelsRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsDOMWindowUtils::ToScreenRectInCSSUnits(float aX, float aY, float aWidth,
|
nsDOMWindowUtils::ToScreenRectInCSSUnits(float aX, float aY, float aWidth,
|
||||||
float aHeight, DOMRect** aResult) {
|
float aHeight, DOMRect** aResult) {
|
||||||
ScreenRect rect;
|
LayoutDeviceRect devRect;
|
||||||
MOZ_TRY_VAR(rect, ConvertToScreenRect(aX, aY, aWidth, aHeight));
|
MOZ_TRY_VAR(devRect, ConvertTo(aX, aY, aWidth, aHeight, CoordsType::Screen));
|
||||||
|
|
||||||
nsPresContext* presContext = GetPresContext();
|
nsPresContext* presContext = GetPresContext();
|
||||||
MOZ_ASSERT(presContext);
|
MOZ_ASSERT(presContext);
|
||||||
|
|
||||||
const auto devRect = ViewAs<LayoutDevicePixel>(
|
|
||||||
rect, PixelCastJustification::ScreenIsParentLayerForRoot);
|
|
||||||
|
|
||||||
// We want to return the screen rect in CSS units of the browser chrome.
|
// We want to return the screen rect in CSS units of the browser chrome.
|
||||||
//
|
//
|
||||||
// TODO(emilio): It'd be cleaner to convert callers to use plain toScreenRect,
|
// TODO(emilio): It'd be cleaner to convert callers to use plain toScreenRect,
|
||||||
@@ -1931,8 +1934,25 @@ nsDOMWindowUtils::ToScreenRectInCSSUnits(float aX, float aY, float aWidth,
|
|||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsDOMWindowUtils::ToScreenRect(float aX, float aY, float aWidth, float aHeight,
|
nsDOMWindowUtils::ToScreenRect(float aX, float aY, float aWidth, float aHeight,
|
||||||
DOMRect** aResult) {
|
DOMRect** aResult) {
|
||||||
ScreenRect rect;
|
LayoutDeviceRect devPixelsRect;
|
||||||
MOZ_TRY_VAR(rect, ConvertToScreenRect(aX, aY, aWidth, aHeight));
|
MOZ_TRY_VAR(devPixelsRect,
|
||||||
|
ConvertTo(aX, aY, aWidth, aHeight, CoordsType::Screen));
|
||||||
|
|
||||||
|
ScreenRect rect = ViewAs<ScreenPixel>(
|
||||||
|
devPixelsRect, PixelCastJustification::ScreenIsParentLayerForRoot);
|
||||||
|
|
||||||
|
RefPtr<DOMRect> outRect = new DOMRect(mWindow);
|
||||||
|
outRect->SetRect(rect.x, rect.y, rect.width, rect.height);
|
||||||
|
outRect.forget(aResult);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsDOMWindowUtils::ToTopLevelWidgetRect(float aX, float aY, float aWidth,
|
||||||
|
float aHeight, DOMRect** aResult) {
|
||||||
|
LayoutDeviceRect rect;
|
||||||
|
MOZ_TRY_VAR(rect,
|
||||||
|
ConvertTo(aX, aY, aWidth, aHeight, CoordsType::TopLevelWidget));
|
||||||
|
|
||||||
RefPtr<DOMRect> outRect = new DOMRect(mWindow);
|
RefPtr<DOMRect> outRect = new DOMRect(mWindow);
|
||||||
outRect->SetRect(rect.x, rect.y, rect.width, rect.height);
|
outRect->SetRect(rect.x, rect.y, rect.width, rect.height);
|
||||||
|
|||||||
@@ -110,8 +110,12 @@ class nsDOMWindowUtils final : public nsIDOMWindowUtils,
|
|||||||
bool aFromChrome);
|
bool aFromChrome);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mozilla::Result<mozilla::ScreenRect, nsresult> ConvertToScreenRect(
|
enum class CoordsType {
|
||||||
float aX, float aY, float aWidth, float aHeight);
|
Screen,
|
||||||
|
TopLevelWidget,
|
||||||
|
};
|
||||||
|
mozilla::Result<mozilla::LayoutDeviceRect, nsresult> ConvertTo(
|
||||||
|
float aX, float aY, float aWidth, float aHeight, CoordsType);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1088,6 +1088,13 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||||||
DOMRect toScreenRect(in float aX, in float aY,
|
DOMRect toScreenRect(in float aX, in float aY,
|
||||||
in float aWidth, in float aHeight);
|
in float aWidth, in float aHeight);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform a rectangle given in coordinates relative to the top level widget
|
||||||
|
* coordinates of this document (i.e. browser.xhml).
|
||||||
|
*/
|
||||||
|
DOMRect toTopLevelWidgetRect(in float aX, in float aY,
|
||||||
|
in float aWidth, in float aHeight);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform a rectangle given in coordinates relative to the top level
|
* Transform a rectangle given in coordinates relative to the top level
|
||||||
* parent process widget to the local widget. This window should be in a
|
* parent process widget to the local widget. This window should be in a
|
||||||
|
|||||||
@@ -25,6 +25,20 @@ export var LayoutUtils = {
|
|||||||
return win.ownerGlobal.windowUtils.toScreenRect(x, y, width, height);
|
return win.ownerGlobal.windowUtils.toScreenRect(x, y, width, height);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert rect into the top level widget coordinates in LayoutDevicePixel
|
||||||
|
* units.
|
||||||
|
*/
|
||||||
|
rectToTopLevelWidgetRect(win, rect) {
|
||||||
|
const { x, y, width, height } = this._rectToClientRect(win, rect);
|
||||||
|
return win.ownerGlobal.windowUtils.toTopLevelWidgetRect(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
_rectToClientRect(win, rect) {
|
_rectToClientRect(win, rect) {
|
||||||
// We need to compensate the position for ancestor iframes in the same
|
// We need to compensate the position for ancestor iframes in the same
|
||||||
// process that might shift things over. Those might have different CSS
|
// process that might shift things over. Those might have different CSS
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ skip-if = ["verify && debug && (os == 'mac' || os == 'linux')"]
|
|||||||
|
|
||||||
["browser_InlineSpellChecker.js"]
|
["browser_InlineSpellChecker.js"]
|
||||||
|
|
||||||
|
["browser_LayoutUtils.js"]
|
||||||
|
|
||||||
["browser_Troubleshoot.js"]
|
["browser_Troubleshoot.js"]
|
||||||
|
|
||||||
["browser_web_channel.js"]
|
["browser_web_channel.js"]
|
||||||
|
|||||||
58
toolkit/modules/tests/browser/browser_LayoutUtils.js
Normal file
58
toolkit/modules/tests/browser/browser_LayoutUtils.js
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
add_task(async function test_rectToBrowserRect() {
|
||||||
|
const tab = await BrowserTestUtils.openNewForegroundTab(
|
||||||
|
gBrowser,
|
||||||
|
"data:text/html;charset=utf-8,test"
|
||||||
|
);
|
||||||
|
|
||||||
|
SpecialPowers.addTaskImport(
|
||||||
|
"LayoutUtils",
|
||||||
|
"resource://gre/modules/LayoutUtils.sys.mjs"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Convert (12, 34) in a content document coordinates into this browser window
|
||||||
|
// coordinates.
|
||||||
|
const positionInBrowser = await SpecialPowers.spawn(
|
||||||
|
tab.linkedBrowser,
|
||||||
|
[],
|
||||||
|
() => {
|
||||||
|
/* global LayoutUtils */
|
||||||
|
return LayoutUtils.rectToTopLevelWidgetRect(content.window, {
|
||||||
|
left: 12,
|
||||||
|
top: 34,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Dispatch a mousedown event on the browser window coordinates position to
|
||||||
|
// see whether it's fired on the correct position in the content document.
|
||||||
|
const mouseDownPromise = BrowserTestUtils.waitForContentEvent(
|
||||||
|
tab.linkedBrowser,
|
||||||
|
"mousedown",
|
||||||
|
false,
|
||||||
|
event => {
|
||||||
|
dump(`mousedown on (${event.clientX}, ${event.clientY})`);
|
||||||
|
return event.clientX == 12 && event.clientY == 34;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// A workaround for bug 1743857.
|
||||||
|
await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
|
||||||
|
await Promise.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
EventUtils.synthesizeMouseAtPoint(
|
||||||
|
positionInBrowser.x / window.devicePixelRatio,
|
||||||
|
positionInBrowser.y / window.devicePixelRatio,
|
||||||
|
{ type: "mousedown", button: 1 }
|
||||||
|
);
|
||||||
|
await mouseDownPromise;
|
||||||
|
|
||||||
|
Assert.ok(true, "LayoutUtils.rectToBrowserRect() works as expected");
|
||||||
|
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user