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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"]
|
||||
|
||||
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