diff --git a/browser/components/sessionstore/SessionStore.jsm b/browser/components/sessionstore/SessionStore.jsm index d4286de76fe..ac2d1ac2a12 100644 --- a/browser/components/sessionstore/SessionStore.jsm +++ b/browser/components/sessionstore/SessionStore.jsm @@ -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) diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index a3dd99a1461..2640c55b9f7 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -5029,25 +5029,30 @@ nsGlobalWindow::SetOuterHeight(JSContext* aCx, JS::Handle 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 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 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 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 diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 3c5ed6587c0..17cde6b4628 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -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); diff --git a/gfx/layers/apz/util/APZEventState.cpp b/gfx/layers/apz/util/APZEventState.cpp index 9b86edd415e..45629a2cea0 100644 --- a/gfx/layers/apz/util/APZEventState.cpp +++ b/gfx/layers/apz/util/APZEventState.cpp @@ -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 diff --git a/gfx/src/nsDeviceContext.cpp b/gfx/src/nsDeviceContext.cpp index 913a9a9a436..41266982c43 100644 --- a/gfx/src/nsDeviceContext.cpp +++ b/gfx/src/nsDeviceContext.cpp @@ -658,6 +658,8 @@ nsDeviceContext::FindScreen(nsIScreen** outScreen) return; } + CheckDPIChange(); + if (mWidget->GetOwningTabChild()) { mScreenManager->ScreenForNativeWidget((void *)mWidget->GetOwningTabChild(), outScreen); diff --git a/layout/base/Units.h b/layout/base/Units.h index db0d2821db4..90cc41d9d8d 100644 --- a/layout/base/Units.h +++ b/layout/base/Units.h @@ -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), diff --git a/layout/xul/nsMenuPopupFrame.cpp b/layout/xul/nsMenuPopupFrame.cpp index 545e7d588a7..90875398c3b 100644 --- a/layout/xul/nsMenuPopupFrame.cpp +++ b/layout/xul/nsMenuPopupFrame.cpp @@ -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, diff --git a/layout/xul/nsMenuPopupFrame.h b/layout/xul/nsMenuPopupFrame.h index 37777c86148..159804fed5d 100644 --- a/layout/xul/nsMenuPopupFrame.h +++ b/layout/xul/nsMenuPopupFrame.h @@ -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 diff --git a/layout/xul/nsResizerFrame.cpp b/layout/xul/nsResizerFrame.cpp index 979418ba77e..aa8993d97d3 100644 --- a/layout/xul/nsResizerFrame.cpp +++ b/layout/xul/nsResizerFrame.cpp @@ -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) { diff --git a/view/nsView.cpp b/view/nsView.cpp index 5d7979e2cc7..f10bafb4c4e 100644 --- a/view/nsView.cpp +++ b/view/nsView.cpp @@ -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! } diff --git a/xpfe/appshell/nsXULWindow.cpp b/xpfe/appshell/nsXULWindow.cpp index af4beb11508..221f1b66934 100644 --- a/xpfe/appshell/nsXULWindow.cpp +++ b/xpfe/appshell/nsXULWindow.cpp @@ -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 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 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 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 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 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 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 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) { diff --git a/xpfe/appshell/nsXULWindow.h b/xpfe/appshell/nsXULWindow.h index 882e6147e4f..589e3cc478a 100644 --- a/xpfe/appshell/nsXULWindow.h +++ b/xpfe/appshell/nsXULWindow.h @@ -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);