Bug 890156 - patch 6 - Update window placement code to work with desktop pixels, for per-monitor DPI support on Windows. r=emk

This commit is contained in:
Jonathan Kew 2015-12-03 13:19:50 +00:00
parent e67b37655a
commit dc85a3172e
12 changed files with 200 additions and 118 deletions

View File

@ -3476,6 +3476,9 @@ var SessionStoreInternal = {
}
// only modify those aspects which aren't correct yet
if (!isNaN(aLeft) && !isNaN(aTop) && (aLeft != win_("screenX") || aTop != win_("screenY"))) {
aWindow.moveTo(aLeft, aTop);
}
if (aWidth && aHeight && (aWidth != win_("width") || aHeight != win_("height"))) {
// Don't resize the window if it's currently maximized and we would
// maximize it again shortly after.
@ -3483,9 +3486,6 @@ var SessionStoreInternal = {
aWindow.resizeTo(aWidth, aHeight);
}
}
if (!isNaN(aLeft) && !isNaN(aTop) && (aLeft != win_("screenX") || aTop != win_("screenY"))) {
aWindow.moveTo(aLeft, aTop);
}
if (aSizeMode && win_("sizemode") != aSizeMode)
{
switch (aSizeMode)

View File

@ -5029,25 +5029,30 @@ nsGlobalWindow::SetOuterHeight(JSContext* aCx, JS::Handle<JS::Value> aValue,
aValue, "outerHeight", aError);
}
nsIntPoint
DesktopIntPoint
nsGlobalWindow::GetScreenXY(ErrorResult& aError)
{
MOZ_ASSERT(IsOuterWindow());
// When resisting fingerprinting, always return (0,0)
if (nsContentUtils::ShouldResistFingerprinting(mDocShell)) {
return nsIntPoint(0, 0);
return DesktopIntPoint(0, 0);
}
nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
if (!treeOwnerAsWin) {
aError.Throw(NS_ERROR_FAILURE);
return nsIntPoint(0, 0);
return DesktopIntPoint(0, 0);
}
int32_t x = 0, y = 0;
aError = treeOwnerAsWin->GetPosition(&x, &y);
return nsIntPoint(x, y);
nsCOMPtr<nsIWidget> widget = GetMainWidget();
DesktopToLayoutDeviceScale scale = widget ? widget->GetDesktopToDeviceScale()
: DesktopToLayoutDeviceScale(1.0);
DesktopPoint pt = LayoutDeviceIntPoint(x, y) / scale;
return DesktopIntPoint(NSToIntRound(pt.x), NSToIntRound(pt.y));
}
int32_t
@ -5055,7 +5060,7 @@ nsGlobalWindow::GetScreenXOuter(ErrorResult& aError)
{
MOZ_RELEASE_ASSERT(IsOuterWindow());
return DevToCSSIntPixels(GetScreenXY(aError).x);
return GetScreenXY(aError).x;
}
int32_t
@ -5299,7 +5304,7 @@ nsGlobalWindow::GetScreenYOuter(ErrorResult& aError)
{
MOZ_RELEASE_ASSERT(IsOuterWindow());
return DevToCSSIntPixels(GetScreenXY(aError).y);
return GetScreenXY(aError).y;
}
int32_t
@ -7002,13 +7007,15 @@ nsGlobalWindow::MoveToOuter(int32_t aXPos, int32_t aYPos, ErrorResult& aError, b
return;
}
// Mild abuse of a "size" object so we don't need more helper functions.
nsIntSize cssPos(aXPos, aYPos);
CheckSecurityLeftAndTop(&cssPos.width, &cssPos.height, aCallerIsChrome);
DesktopIntPoint pt(aXPos, aYPos);
CheckSecurityLeftAndTop(&pt.x, &pt.y, aCallerIsChrome);
nsIntSize devPos = CSSToDevIntPixels(cssPos);
nsCOMPtr<nsIWidget> widget = GetMainWidget();
DesktopToLayoutDeviceScale scale = widget ? widget->GetDesktopToDeviceScale()
: DesktopToLayoutDeviceScale(1.0);
LayoutDevicePoint devPos = pt * scale;
aError = treeOwnerAsWin->SetPosition(devPos.width, devPos.height);
aError = treeOwnerAsWin->SetPosition(devPos.x, devPos.y);
}
void

View File

@ -1606,8 +1606,8 @@ protected:
// Outer windows only.
void PreloadLocalStorage();
// Returns device pixels. Outer windows only.
nsIntPoint GetScreenXY(mozilla::ErrorResult& aError);
// Returns desktop pixels. Outer windows only.
mozilla::DesktopIntPoint GetScreenXY(mozilla::ErrorResult& aError);
nsGlobalWindow* InnerForSetTimeoutOrInterval(mozilla::ErrorResult& aError);

View File

@ -181,7 +181,7 @@ APZEventState::ProcessSingleTap(const CSSPoint& aPoint,
LayoutDevicePoint currentPoint =
APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid)
* widget->GetDefaultScale();;
* widget->GetDefaultScale();
if (!mActiveElementManager->ActiveElementUsesStyle()) {
// If the active element isn't visually affected by the :active style, we
// have no need to wait the extra sActiveDurationMs to make the activation

View File

@ -658,6 +658,8 @@ nsDeviceContext::FindScreen(nsIScreen** outScreen)
return;
}
CheckDPIChange();
if (mWidget->GetOwningTabChild()) {
mScreenManager->ScreenForNativeWidget((void *)mWidget->GetOwningTabChild(),
outScreen);

View File

@ -302,6 +302,10 @@ struct LayoutDevicePixel {
return LayoutDeviceIntRect::FromUnknownRect(aRect.ToNearestPixels(aAppUnitsPerDevPixel));
}
static LayoutDeviceIntRect FromAppUnitsToInside(const nsRect& aRect, nscoord aAppUnitsPerDevPixel) {
return LayoutDeviceIntRect::FromUnknownRect(aRect.ToInsidePixels(aAppUnitsPerDevPixel));
}
static LayoutDeviceIntSize FromAppUnitsRounded(const nsSize& aSize, nscoord aAppUnitsPerDevPixel) {
return LayoutDeviceIntSize(
NSAppUnitsToIntPixels(aSize.width, aAppUnitsPerDevPixel),

View File

@ -1428,8 +1428,17 @@ nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame, bool aIsMove, bool aS
// If a panel is being moved or has flip="none", don't constrain or flip it. But always do this for
// content shells, so that the popup doesn't extend outside the containing frame.
if (mInContentShell || (mFlip != FlipType_None && (!aIsMove || mPopupType != ePopupTypePanel))) {
nsRect screenRect = GetConstraintRect(anchorRect, rootScreenRect, popupLevel);
if (mInContentShell || (mFlip != FlipType_None &&
(!aIsMove || mPopupType != ePopupTypePanel))) {
int32_t appPerDev = presContext->AppUnitsPerDevPixel();
LayoutDeviceIntRect anchorRectDevPix =
LayoutDeviceIntRect::FromAppUnitsToNearest(anchorRect, appPerDev);
LayoutDeviceIntRect rootScreenRectDevPix =
LayoutDeviceIntRect::FromAppUnitsToNearest(rootScreenRect, appPerDev);
LayoutDeviceIntRect screenRectDevPix =
GetConstraintRect(anchorRectDevPix, rootScreenRectDevPix, popupLevel);
nsRect screenRect =
LayoutDeviceIntRect::ToAppUnits(screenRectDevPix, appPerDev);
// Ensure that anchorRect is on screen.
anchorRect = anchorRect.Intersect(screenRect);
@ -1527,13 +1536,12 @@ nsMenuPopupFrame::GetCurrentMenuItem()
return mCurrentMenu;
}
nsRect
nsMenuPopupFrame::GetConstraintRect(const nsRect& aAnchorRect,
const nsRect& aRootScreenRect,
LayoutDeviceIntRect
nsMenuPopupFrame::GetConstraintRect(const LayoutDeviceIntRect& aAnchorRect,
const LayoutDeviceIntRect& aRootScreenRect,
nsPopupLevel aPopupLevel)
{
nsIntRect screenRectPixels;
nsPresContext* presContext = PresContext();
LayoutDeviceIntRect screenRectPixels;
// determine the available screen space. It will be reduced by the OS chrome
// such as menubars. It addition, for content shells, it will be the area of
@ -1545,13 +1553,10 @@ nsMenuPopupFrame::GetConstraintRect(const nsRect& aAnchorRect,
// This is because we need to constrain the content to this content area,
// so we should use the same screen. Otherwise, use the screen where the
// anchor is located.
nsRect rect = mInContentShell ? aRootScreenRect : aAnchorRect;
// nsIScreenManager::ScreenForRect wants the coordinates in CSS pixels
int32_t width = std::max(1, nsPresContext::AppUnitsToIntCSSPixels(rect.width));
int32_t height = std::max(1, nsPresContext::AppUnitsToIntCSSPixels(rect.height));
sm->ScreenForRect(nsPresContext::AppUnitsToIntCSSPixels(rect.x),
nsPresContext::AppUnitsToIntCSSPixels(rect.y),
width, height, getter_AddRefs(screen));
LayoutDeviceIntRect rect = mInContentShell ? aRootScreenRect : aAnchorRect;
int32_t width = std::max(1, rect.width);
int32_t height = std::max(1, rect.height);
sm->ScreenForRect(rect.x, rect.y, width, height, getter_AddRefs(screen));
if (screen) {
// Non-top-level popups (which will always be panels)
// should never overlap the OS bar:
@ -1559,20 +1564,19 @@ nsMenuPopupFrame::GetConstraintRect(const nsRect& aAnchorRect,
// get the total screen area if the popup is allowed to overlap it.
if (!dontOverlapOSBar && mMenuCanOverlapOSBar && !mInContentShell)
screen->GetRect(&screenRectPixels.x, &screenRectPixels.y,
&screenRectPixels.width, &screenRectPixels.height);
&screenRectPixels.width, &screenRectPixels.height);
else
screen->GetAvailRect(&screenRectPixels.x, &screenRectPixels.y,
&screenRectPixels.width, &screenRectPixels.height);
&screenRectPixels.width, &screenRectPixels.height);
}
}
nsRect screenRect = ToAppUnits(screenRectPixels, presContext->AppUnitsPerDevPixel());
if (mInContentShell) {
// for content shells, clip to the client area rather than the screen area
screenRect.IntersectRect(screenRect, aRootScreenRect);
screenRectPixels.IntersectRect(screenRectPixels, aRootScreenRect);
}
return screenRect;
return screenRectPixels;
}
void nsMenuPopupFrame::CanAdjustEdges(int8_t aHorizontalSide,

View File

@ -362,8 +362,11 @@ public:
// For non-toplevel popups (which will always be panels), we will also
// constrain them to the available screen rect, ie they will not fall
// underneath the taskbar, dock or other fixed OS elements.
nsRect GetConstraintRect(const nsRect& aAnchorRect, const nsRect& aRootScreenRect,
nsPopupLevel aPopupLevel);
// This operates in device pixels.
mozilla::LayoutDeviceIntRect
GetConstraintRect(const mozilla::LayoutDeviceIntRect& aAnchorRect,
const mozilla::LayoutDeviceIntRect& aRootScreenRect,
nsPopupLevel aPopupLevel);
// Determines whether the given edges of the popup may be moved, where
// aHorizontalSide and aVerticalSide are one of the NS_SIDE_* constants, or

View File

@ -228,12 +228,15 @@ nsResizerFrame::HandleEvent(nsPresContext* aPresContext,
nsRect rootScreenRect = rootFrame->GetScreenRectInAppUnits();
nsPopupLevel popupLevel = menuPopupFrame->PopupLevel();
nsRect screenRect = menuPopupFrame->GetConstraintRect(frameRect, rootScreenRect, popupLevel);
// round using ToInsidePixels as it's better to be a pixel too small
// than be too large. If the popup is too large it could get flipped
// to the opposite side of the anchor point while resizing.
nsIntRect screenRectPixels = screenRect.ToInsidePixels(aPresContext->AppUnitsPerDevPixel());
rect.IntersectRect(rect, LayoutDeviceIntRect::FromUnknownRect(screenRectPixels));
int32_t appPerDev = aPresContext->AppUnitsPerDevPixel();
LayoutDeviceIntRect screenRect = menuPopupFrame->GetConstraintRect
(LayoutDeviceIntRect::FromAppUnitsToNearest(frameRect, appPerDev),
// round using ...ToInside as it's better to be a pixel too small
// than be too large. If the popup is too large it could get flipped
// to the opposite side of the anchor point while resizing.
LayoutDeviceIntRect::FromAppUnitsToInside(rootScreenRect, appPerDev),
popupLevel);
rect.IntersectRect(rect, screenRect);
}
if (contentToResize) {

View File

@ -336,44 +336,43 @@ void nsView::DoResetWidgetBounds(bool aMoveOnly,
// Child views are never attached to top level widgets, this is safe.
// Coordinates are converted to display pixels for window Move/Resize APIs,
// Coordinates are converted to desktop pixels for window Move/Resize APIs,
// because of the potential for device-pixel coordinate spaces for mixed
// hidpi/lodpi screens to overlap each other and result in bad placement
// (bug 814434).
double invScale;
DesktopToLayoutDeviceScale scale = widget->GetDesktopToDeviceScale();
// Bug 861270: for correct widget manipulation at arbitrary scale factors,
// prefer to base scaling on widget->GetDefaultScale(). But only do this if
// it matches the view manager's device context scale after allowing for the
// quantization to app units, because of OS X multiscreen issues (where the
// only two scales are 1.0 or 2.0, and so the quantization doesn't actually
// cause problems anyhow).
// In the case of a mismatch, fall back to scaling based on the dev context's
// AppUnitsPerDevPixelAtUnitFullZoom value. On platforms where the device-pixel
// scale is uniform across all displays (currently all except OS X), we'll
// always use the precise value from mWindow->GetDefaultScale here.
CSSToLayoutDeviceScale scale = widget->GetDefaultScale();
if (NSToIntRound(60.0 / scale.scale) == dx->AppUnitsPerDevPixelAtUnitFullZoom()) {
invScale = 1.0 / scale.scale;
} else {
invScale = dx->AppUnitsPerDevPixelAtUnitFullZoom() / 60.0;
#ifdef XP_MACOSX
// On OS X, this can be called before Cocoa has updated the backing scale
// factor of our widget, in which case |scale| is wrong here. To work
// around this, we check the device context and override |scale| if it
// doesn't match. (This happens when a popup window that has previously
// been created and hidden is being moved between hi- and lo-dpi screens,
// but is not currently visible; Cocoa doesn't notify it of the scale
// factor change until it gets shown on the new screen, which is too late
// for us because we'll have already done the computations involving scale
// here to move/size it.)
// It might be better to avoid this by keeping calculations such as
// CalcWidgetBounds entirely in appUnits, rather than using device pixels,
// but that seems like a more extensive and potentially risky change.
int32_t appPerDev = dx->AppUnitsPerDevPixelAtUnitFullZoom();
if (NSToIntRound(60.0 / scale.scale) != appPerDev) {
scale = DesktopToLayoutDeviceScale(60.0 / appPerDev);
}
#endif
DesktopRect deskRect = newBounds / scale;
if (changedPos) {
if (changedSize && !aMoveOnly) {
widget->ResizeClient(newBounds.x * invScale,
newBounds.y * invScale,
newBounds.width * invScale,
newBounds.height * invScale,
widget->ResizeClient(deskRect.x, deskRect.y,
deskRect.width, deskRect.height,
aInvalidateChangedSize);
} else {
widget->MoveClient(newBounds.x * invScale,
newBounds.y * invScale);
widget->MoveClient(deskRect.x, deskRect.y);
}
} else {
if (changedSize && !aMoveOnly) {
widget->ResizeClient(newBounds.width * invScale,
newBounds.height * invScale,
widget->ResizeClient(deskRect.width, deskRect.height,
aInvalidateChangedSize);
} // else do nothing!
}

View File

@ -569,13 +569,51 @@ NS_IMETHODIMP nsXULWindow::GetUnscaledDevicePixelsPerCSSPixel(double *aScale)
return NS_OK;
}
DesktopToLayoutDeviceScale
nsXULWindow::GetScaleForDestinationPosition(int32_t aX, int32_t aY)
{
DesktopToLayoutDeviceScale scale(nsIWidget::DefaultScaleOverride());
if (scale.scale <= 0.0) {
// The destination monitor may have the different dpi from the source.
nsCOMPtr<nsIScreenManager> screenMgr(do_GetService(
"@mozilla.org/gfx/screenmanager;1"));
if (screenMgr) {
int32_t width, height;
// Use current size, converted to desktop pixels
GetSize(&width, &height);
DesktopToLayoutDeviceScale curr = mWindow->GetDesktopToDeviceScale();
width /= curr.scale;
height /= curr.scale;
width = std::max(1, width);
height = std::max(1, height);
nsCOMPtr<nsIScreen> screen;
screenMgr->ScreenForRect(aX, aY, width, height,
getter_AddRefs(screen));
if (screen) {
double contentsScaleFactor;
if (NS_SUCCEEDED(screen->GetContentsScaleFactor(
&contentsScaleFactor))) {
scale = DesktopToLayoutDeviceScale(contentsScaleFactor);
} else {
// Fallback to the scale from the widget.
scale = mWindow->GetDesktopToDeviceScale();
}
}
} else {
// this fallback should never actually be needed
scale = mWindow->GetDesktopToDeviceScale();
}
}
return scale;
}
NS_IMETHODIMP nsXULWindow::SetPosition(int32_t aX, int32_t aY)
{
// Don't reset the window's size mode here - platforms that don't want to move
// maximized windows should reset it in their respective Move implementation.
CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale();
double invScale = 1.0 / scale.scale;
nsresult rv = mWindow->Move(aX * invScale, aY * invScale);
DesktopToLayoutDeviceScale scale = GetScaleForDestinationPosition(aX, aY);
DesktopPoint pos = LayoutDeviceIntPoint(aX, aY) / scale;
nsresult rv = mWindow->Move(pos.x, pos.y);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
if (!mChromeLoaded) {
// If we're called before the chrome is loaded someone obviously wants this
@ -602,9 +640,9 @@ NS_IMETHODIMP nsXULWindow::SetSize(int32_t aCX, int32_t aCY, bool aRepaint)
mIntrinsicallySized = false;
CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale();
double invScale = 1.0 / scale.scale;
nsresult rv = mWindow->Resize(aCX * invScale, aCY * invScale, aRepaint);
DesktopToLayoutDeviceScale scale = mWindow->GetDesktopToDeviceScale();
DesktopSize size = LayoutDeviceIntSize(aCX, aCY) / scale;
nsresult rv = mWindow->Resize(size.width, size.height, aRepaint);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
if (!mChromeLoaded) {
// If we're called before the chrome is loaded someone obviously wants this
@ -635,10 +673,9 @@ NS_IMETHODIMP nsXULWindow::SetPositionAndSize(int32_t aX, int32_t aY,
mIntrinsicallySized = false;
CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale();
double invScale = 1.0 / scale.scale;
nsresult rv = mWindow->Resize(aX * invScale, aY * invScale,
aCX * invScale, aCY * invScale,
DesktopToLayoutDeviceScale scale = mWindow->GetDesktopToDeviceScale();
DesktopRect rect = LayoutDeviceIntRect(aX, aY, aCX, aCY) / scale;
nsresult rv = mWindow->Resize(rect.x, rect.y, rect.width, rect.height,
aRepaint);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
if (!mChromeLoaded) {
@ -706,8 +743,7 @@ NS_IMETHODIMP nsXULWindow::Center(nsIXULWindow *aRelative, bool aScreen, bool aA
result = base->GetPositionAndSize(&left, &top, &width, &height);
if (NS_SUCCEEDED(result)) {
double scale;
if (NS_SUCCEEDED(base->GetUnscaledDevicePixelsPerCSSPixel(&scale))) {
// convert device-pixel coordinates to global display pixels
if (NS_SUCCEEDED(base->GetDevicePixelsPerDesktopPixel(&scale))) {
left = NSToIntRound(left / scale);
top = NSToIntRound(top / scale);
width = NSToIntRound(width / scale);
@ -744,18 +780,28 @@ NS_IMETHODIMP nsXULWindow::Center(nsIXULWindow *aRelative, bool aScreen, bool aA
if (screenCoordinates || windowCoordinates) {
NS_ASSERTION(mWindow, "what, no window?");
CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale();
double scale = mWindow->GetDesktopToDeviceScale().scale;
GetSize(&ourWidth, &ourHeight);
ourWidth = NSToIntRound(ourWidth / scale.scale);
ourHeight = NSToIntRound(ourHeight / scale.scale);
left += (width - ourWidth) / 2;
top += (height - ourHeight) / (aAlert ? 3 : 2);
int32_t scaledWidth, scaledHeight;
scaledWidth = NSToIntRound(ourWidth / scale);
scaledHeight = NSToIntRound(ourHeight / scale);
left += (width - scaledWidth) / 2;
top += (height - scaledHeight) / (aAlert ? 3 : 2);
if (windowCoordinates) {
mWindow->ConstrainPosition(false, &left, &top);
}
SetPosition(left * scale.scale, top * scale.scale);
SetPosition(left * scale, top * scale);
// If moving the window caused it to change size,
// re-do the centering.
int32_t newWidth, newHeight;
GetSize(&newWidth, &newHeight);
if (newWidth != ourWidth || newHeight != ourHeight) {
return Center(aRelative, aScreen, aAlert);
}
return NS_OK;
}
return NS_ERROR_FAILURE;
}
@ -1020,6 +1066,19 @@ void nsXULWindow::OnChromeLoaded()
mChromeLoaded = true;
ApplyChromeFlags();
SyncAttributesToWidget();
bool positionSet = !mIgnoreXULPosition;
nsCOMPtr<nsIXULWindow> parentWindow(do_QueryReferent(mParentWindow));
#if defined(XP_UNIX) && !defined(XP_MACOSX)
// don't override WM placement on unix for independent, top-level windows
// (however, we think the benefits of intelligent dependent window placement
// trump that override.)
if (!parentWindow)
positionSet = false;
#endif
if (positionSet)
positionSet = LoadPositionFromXUL();
if (!mIgnoreXULSize)
LoadSizeFromXUL();
if (mIntrinsicallySized) {
@ -1041,17 +1100,6 @@ void nsXULWindow::OnChromeLoaded()
}
}
bool positionSet = !mIgnoreXULPosition;
nsCOMPtr<nsIXULWindow> parentWindow(do_QueryReferent(mParentWindow));
#if defined(XP_UNIX) && !defined(XP_MACOSX)
// don't override WM placement on unix for independent, top-level windows
// (however, we think the benefits of intelligent dependent window placement
// trump that override.)
if (!parentWindow)
positionSet = false;
#endif
if (positionSet)
positionSet = LoadPositionFromXUL();
LoadMiscPersistentAttributesFromXUL();
if (mCenterAfterLoad && !positionSet)
@ -1089,11 +1137,11 @@ bool nsXULWindow::LoadPositionFromXUL()
// Convert to global display pixels for consistent window management across
// screens with diverse resolutions
CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale();
currX = NSToIntRound(currX / scale.scale);
currY = NSToIntRound(currY / scale.scale);
currWidth = NSToIntRound(currWidth / scale.scale);
currHeight = NSToIntRound(currHeight / scale.scale);
double scale = mWindow->GetDesktopToDeviceScale().scale;
currX = NSToIntRound(currX / scale);
currY = NSToIntRound(currY / scale);
currWidth = NSToIntRound(currWidth / scale);
currHeight = NSToIntRound(currHeight / scale);
// Obtain the position information from the <xul:window> element.
int32_t specX = currX;
@ -1120,7 +1168,7 @@ bool nsXULWindow::LoadPositionFromXUL()
int32_t parentX, parentY;
if (NS_SUCCEEDED(parent->GetPosition(&parentX, &parentY))) {
double scale;
if (NS_SUCCEEDED(parent->GetUnscaledDevicePixelsPerCSSPixel(&scale))) {
if (NS_SUCCEEDED(parent->GetDevicePixelsPerDesktopPixel(&scale))) {
parentX = NSToIntRound(parentX / scale);
parentY = NSToIntRound(parentY / scale);
}
@ -1134,8 +1182,10 @@ bool nsXULWindow::LoadPositionFromXUL()
}
mWindow->ConstrainPosition(false, &specX, &specY);
if (specX != currX || specY != currY) {
CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale();
SetPosition(specX * scale.scale, specY * scale.scale);
DesktopToLayoutDeviceScale destScale =
GetScaleForDestinationPosition(specX, specY);
LayoutDevicePoint devPos = DesktopIntPoint(specX, specY) * destScale;
SetPosition(devPos.x, devPos.y);
}
return gotPosition;
@ -1160,11 +1210,12 @@ bool nsXULWindow::LoadSizeFromXUL()
NS_ASSERTION(mWindow, "we expected to have a window already");
CSSToLayoutDeviceScale scale = mWindow ? mWindow->GetDefaultScale()
: CSSToLayoutDeviceScale(1.0);
GetSize(&currWidth, &currHeight);
currWidth = NSToIntRound(currWidth / scale.scale);
currHeight = NSToIntRound(currHeight / scale.scale);
double displayToDevPx =
mWindow ? mWindow->GetDesktopToDeviceScale().scale : 1.0;
double cssToDevPx = mWindow ? mWindow->GetDefaultScale().scale : 1.0;
currWidth = NSToIntRound(currWidth * displayToDevPx / cssToDevPx);
currHeight = NSToIntRound(currHeight * displayToDevPx / cssToDevPx);
// Obtain the position and sizing information from the <xul:window> element.
int32_t specWidth = currWidth;
@ -1193,7 +1244,7 @@ bool nsXULWindow::LoadSizeFromXUL()
if (screen) {
int32_t screenWidth;
int32_t screenHeight;
screen->GetAvailWidth(&screenWidth);
screen->GetAvailWidth(&screenWidth); // CSS pixels
screen->GetAvailHeight(&screenHeight);
if (specWidth > screenWidth)
specWidth = screenWidth;
@ -1204,8 +1255,7 @@ bool nsXULWindow::LoadSizeFromXUL()
mIntrinsicallySized = false;
if (specWidth != currWidth || specHeight != currHeight) {
CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale();
SetSize(specWidth * scale.scale, specHeight * scale.scale, false);
SetSize(specWidth * cssToDevPx, specHeight * cssToDevPx, false);
}
}
@ -1497,7 +1547,9 @@ NS_IMETHODIMP nsXULWindow::SavePersistentAttributes()
LayoutDeviceIntRect rect;
bool gotRestoredBounds = NS_SUCCEEDED(mWindow->GetRestoredBounds(rect));
CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale();
// we use CSS pixels for size, but desktop pixels for position
CSSToLayoutDeviceScale sizeScale = mWindow->GetDefaultScale();
DesktopToLayoutDeviceScale posScale = mWindow->GetDesktopToDeviceScale();
// make our position relative to our parent, if any
nsCOMPtr<nsIBaseWindow> parent(do_QueryReferent(mParentWindow));
@ -1525,7 +1577,8 @@ NS_IMETHODIMP nsXULWindow::SavePersistentAttributes()
// (only for size elements which are persisted)
if ((mPersistentAttributesDirty & PAD_POSITION) && gotRestoredBounds) {
if (persistString.Find("screenX") >= 0) {
PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.x / scale.scale));
PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d",
NSToIntRound(rect.x / posScale.scale));
sizeString.AssignWithConversion(sizeBuf);
docShellElement->SetAttribute(SCREENX_ATTRIBUTE, sizeString, rv);
if (shouldPersist) {
@ -1533,7 +1586,8 @@ NS_IMETHODIMP nsXULWindow::SavePersistentAttributes()
}
}
if (persistString.Find("screenY") >= 0) {
PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.y / scale.scale));
PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d",
NSToIntRound(rect.y / posScale.scale));
sizeString.AssignWithConversion(sizeBuf);
docShellElement->SetAttribute(SCREENY_ATTRIBUTE, sizeString, rv);
if (shouldPersist) {
@ -1544,7 +1598,8 @@ NS_IMETHODIMP nsXULWindow::SavePersistentAttributes()
if ((mPersistentAttributesDirty & PAD_SIZE) && gotRestoredBounds) {
if (persistString.Find("width") >= 0) {
PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.width / scale.scale));
PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d",
NSToIntRound(rect.width / sizeScale.scale));
sizeString.AssignWithConversion(sizeBuf);
docShellElement->SetAttribute(WIDTH_ATTRIBUTE, sizeString, rv);
if (shouldPersist) {
@ -1552,7 +1607,8 @@ NS_IMETHODIMP nsXULWindow::SavePersistentAttributes()
}
}
if (persistString.Find("height") >= 0) {
PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.height / scale.scale));
PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d",
NSToIntRound(rect.height / sizeScale.scale));
sizeString.AssignWithConversion(sizeBuf);
docShellElement->SetAttribute(HEIGHT_ATTRIBUTE, sizeString, rv);
if (shouldPersist) {

View File

@ -18,6 +18,7 @@
#include "nsWeakReference.h"
#include "nsCOMArray.h"
#include "nsRect.h"
#include "Units.h"
// Interfaces needed
#include "nsIBaseWindow.h"
@ -89,6 +90,9 @@ protected:
NS_IMETHOD EnsurePrompter();
NS_IMETHOD EnsureAuthPrompter();
mozilla::DesktopToLayoutDeviceScale
GetScaleForDestinationPosition(int32_t aX, int32_t aY);
void OnChromeLoaded();
void StaggerPosition(int32_t &aRequestedX, int32_t &aRequestedY,
int32_t aSpecWidth, int32_t aSpecHeight);