Bug 1885106 - Implement LayoutUtils.rectToTopLevelWidgetRect. r=layout-reviewers,emilio

Differential Revision: https://phabricator.services.mozilla.com/D211131
This commit is contained in:
Hiroyuki Ikezoe
2024-06-18 22:00:49 +00:00
parent 21e2cd2085
commit e0e70e4bd0
6 changed files with 120 additions and 15 deletions

View File

@@ -1856,8 +1856,8 @@ nsDOMWindowUtils::TransformRectLayoutToVisual(float aX, float aY, float aWidth,
return NS_OK;
}
Result<mozilla::ScreenRect, nsresult> nsDOMWindowUtils::ConvertToScreenRect(
float aX, float aY, float aWidth, float aHeight) {
Result<mozilla::LayoutDeviceRect, nsresult> nsDOMWindowUtils::ConvertTo(
float aX, float aY, float aWidth, float aHeight, CoordsType aCoordsType) {
nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
if (!window) {
return Err(NS_ERROR_NOT_AVAILABLE);
@@ -1894,25 +1894,28 @@ Result<mozilla::ScreenRect, nsresult> nsDOMWindowUtils::ConvertToScreenRect(
LayoutDeviceRect devPixelsRect = LayoutDeviceRect::FromAppUnits(
appUnitsRect, presContext->AppUnitsPerDevPixel());
devPixelsRect =
widget->WidgetToTopLevelWidgetTransform().TransformBounds(devPixelsRect) +
widget->TopLevelWidgetToScreenOffset();
widget->WidgetToTopLevelWidgetTransform().TransformBounds(devPixelsRect);
return ViewAs<ScreenPixel>(
devPixelsRect, PixelCastJustification::ScreenIsParentLayerForRoot);
switch (aCoordsType) {
case CoordsType::Screen:
devPixelsRect += widget->TopLevelWidgetToScreenOffset();
break;
case CoordsType::TopLevelWidget:
// There's nothing to do.
break;
}
return devPixelsRect;
}
NS_IMETHODIMP
nsDOMWindowUtils::ToScreenRectInCSSUnits(float aX, float aY, float aWidth,
float aHeight, DOMRect** aResult) {
ScreenRect rect;
MOZ_TRY_VAR(rect, ConvertToScreenRect(aX, aY, aWidth, aHeight));
LayoutDeviceRect devRect;
MOZ_TRY_VAR(devRect, ConvertTo(aX, aY, aWidth, aHeight, CoordsType::Screen));
nsPresContext* presContext = GetPresContext();
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.
//
// 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
nsDOMWindowUtils::ToScreenRect(float aX, float aY, float aWidth, float aHeight,
DOMRect** aResult) {
ScreenRect rect;
MOZ_TRY_VAR(rect, ConvertToScreenRect(aX, aY, aWidth, aHeight));
LayoutDeviceRect devPixelsRect;
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);
outRect->SetRect(rect.x, rect.y, rect.width, rect.height);

View File

@@ -110,8 +110,12 @@ class nsDOMWindowUtils final : public nsIDOMWindowUtils,
bool aFromChrome);
private:
mozilla::Result<mozilla::ScreenRect, nsresult> ConvertToScreenRect(
float aX, float aY, float aWidth, float aHeight);
enum class CoordsType {
Screen,
TopLevelWidget,
};
mozilla::Result<mozilla::LayoutDeviceRect, nsresult> ConvertTo(
float aX, float aY, float aWidth, float aHeight, CoordsType);
};
#endif

View File

@@ -1088,6 +1088,13 @@ interface nsIDOMWindowUtils : nsISupports {
DOMRect toScreenRect(in float aX, in float aY,
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
* parent process widget to the local widget. This window should be in a

View File

@@ -25,6 +25,20 @@ export var LayoutUtils = {
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) {
// We need to compensate the position for ancestor iframes in the same
// process that might shift things over. Those might have different CSS

View File

@@ -41,6 +41,8 @@ skip-if = ["verify && debug && (os == 'mac' || os == 'linux')"]
["browser_InlineSpellChecker.js"]
["browser_LayoutUtils.js"]
["browser_Troubleshoot.js"]
["browser_web_channel.js"]

View 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);
});