From 229b3f0529ff8a16f6b88d59196a04182a0f55db Mon Sep 17 00:00:00 2001 From: Jan Horak Date: Tue, 23 Oct 2018 12:49:21 +0000 Subject: [PATCH] Bug 1493081 - Added nsIWidget::GetDesktopToDeviceScaleByScreen for scale factor lookup by window position; r=mattwoodrow We've added nsIWidget::GetDesktopToDeviceScaleByScreen which will return scale factor of the newly placed window according to its position on the display. This change is to move implementation to the nsIWidget derived classes. We need that for GTK Wayland, because on the Wayland we cannot determine absolute position of the window, we need to use parent's window scale factor. For other platforms the GetDesktopToDeviceScaleByScreen is implemented in nsBaseWidget. Differential Revision: https://phabricator.services.mozilla.com/D7290 --HG-- extra : moz-landing-system : lando --- view/nsView.cpp | 4 ++-- widget/gtk/nsWindow.cpp | 32 ++++++++++++++++++++++++++++++++ widget/gtk/nsWindow.h | 1 + widget/nsBaseWidget.cpp | 8 ++++++++ widget/nsBaseWidget.h | 3 +++ widget/nsIWidget.h | 7 +++++++ 6 files changed, 53 insertions(+), 2 deletions(-) diff --git a/view/nsView.cpp b/view/nsView.cpp index 8acedb73d731..3f17afc92c4c 100644 --- a/view/nsView.cpp +++ b/view/nsView.cpp @@ -320,7 +320,6 @@ void nsView::DoResetWidgetBounds(bool aMoveOnly, // Stash a copy of these and use them so we can handle this being deleted (say // from sync painting/flushing from Show/Move/Resize on the widget). LayoutDeviceIntRect newBounds; - RefPtr dx = mViewManager->GetDeviceContext(); nsWindowType type = widget->WindowType(); @@ -360,7 +359,8 @@ void nsView::DoResetWidgetBounds(bool aMoveOnly, // 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). - DesktopToLayoutDeviceScale scale = dx->GetDesktopToDeviceScale(); + + DesktopToLayoutDeviceScale scale = widget->GetDesktopToDeviceScaleByScreen(); DesktopRect deskRect = newBounds / scale; if (changedPos) { diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 5203b24f28dc..8957d4755bf4 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -57,6 +57,7 @@ #if defined(MOZ_WAYLAND) #include +#include "nsView.h" #endif #include "nsGkAtoms.h" @@ -841,6 +842,37 @@ nsWindow::GetDesktopToDeviceScale() return DesktopToLayoutDeviceScale(1.0); } +DesktopToLayoutDeviceScale +nsWindow::GetDesktopToDeviceScaleByScreen() +{ +#ifdef MOZ_WAYLAND + GdkDisplay* gdkDisplay = gdk_display_get_default(); + // In Wayland there's no way to get absolute position of the window and use it to + // determine the screen factor of the monitor on which the window is placed. + // The window is notified of the current scale factor but not at this point, + // so the GdkScaleFactor can return wrong value which can lead to wrong popup + // placement. + // We need to use parent's window scale factor for the new one. + if (GDK_IS_WAYLAND_DISPLAY(gdkDisplay)) { + nsView* view = nsView::GetViewFor(this); + if (view) { + nsView* parentView = view->GetParent(); + if (parentView) { + nsIWidget* parentWidget = parentView->GetNearestWidget(nullptr); + if (parentWidget) { + return DesktopToLayoutDeviceScale(parentWidget->RoundsWidgetCoordinatesTo()); + } else { + NS_WARNING("Widget has no parent"); + } + } + } else { + NS_WARNING("Cannot find widget view"); + } + } +#endif + return nsBaseWidget::GetDesktopToDeviceScale(); +} + void nsWindow::SetParent(nsIWidget *aNewParent) { diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h index d3f0182745d5..f0ad1ebaf83b 100644 --- a/widget/gtk/nsWindow.h +++ b/widget/gtk/nsWindow.h @@ -125,6 +125,7 @@ public: virtual float GetDPI() override; virtual double GetDefaultScaleInternal() override; mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() override; + mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScaleByScreen() override; virtual void SetParent(nsIWidget* aNewParent) override; virtual void SetModal(bool aModal) override; virtual bool IsVisible() const override; diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index c47707b000f7..38a9d2ff5299 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -84,6 +84,8 @@ #include "mozilla/layers/CompositorSession.h" #include "VRManagerChild.h" #include "gfxConfig.h" +#include "nsView.h" +#include "nsViewManager.h" #ifdef DEBUG #include "nsIObserver.h" @@ -2090,6 +2092,12 @@ nsBaseWidget::GetWidgetScreen() return screen.forget(); } +mozilla::DesktopToLayoutDeviceScale +nsBaseWidget::GetDesktopToDeviceScaleByScreen() +{ + return (nsView::GetViewFor(this)->GetViewManager()->GetDeviceContext())->GetDesktopToDeviceScale(); +} + nsresult nsIWidget::SynthesizeNativeTouchTap(LayoutDeviceIntPoint aPoint, bool aLongTap, nsIObserver* aObserver) diff --git a/widget/nsBaseWidget.h b/widget/nsBaseWidget.h index 947424ca2390..013b51bdd64b 100644 --- a/widget/nsBaseWidget.h +++ b/widget/nsBaseWidget.h @@ -24,6 +24,7 @@ #include "nsIWidgetListener.h" #include "nsPIDOMWindow.h" #include "nsWeakReference.h" + #include #if defined(XP_WIN) @@ -238,6 +239,8 @@ public: mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() override { return mozilla::DesktopToLayoutDeviceScale(1.0); } + mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScaleByScreen() override; + virtual void ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY) override {} diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 2ae236124883..e8fa4ec88300 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -577,6 +577,13 @@ class nsIWidget : public nsISupports */ virtual mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() = 0; + /** + * Return the scaling factor between device pixels and the platform- + * dependent "desktop pixels" by looking up the screen by the position + * of the widget. + */ + virtual mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScaleByScreen() = 0; + /** * Return the default scale factor for the window. This is the * default number of device pixels per CSS pixel to use. This should