Bug 1493081 - Added nsIWidget::GetDesktopToDeviceScaleByScreen for scale factor lookup by window position; r=mattwoodrow
authorJan Horak <jhorak@redhat.com>
Tue, 23 Oct 2018 12:49:21 +0000
changeset 499022 33523dc590feb2d339e4722fdfe1222d341bead4
parent 499021 5197974fa161114a0543ef2924b53343d84aae6a
child 499023 bc350062ad1b45d628e05ee715ff51d1f4d8bcdc
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1493081
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
view/nsView.cpp
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
widget/nsBaseWidget.cpp
widget/nsBaseWidget.h
widget/nsIWidget.h
--- a/view/nsView.cpp
+++ b/view/nsView.cpp
@@ -315,17 +315,16 @@ void nsView::DoResetWidgetBounds(bool aM
   MOZ_ASSERT(mWindow, "Why was this called??");
 
   // Hold this ref to make sure it stays alive.
   nsCOMPtr<nsIWidget> widget = mWindow;
 
   // 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<nsDeviceContext> dx = mViewManager->GetDeviceContext();
 
   nsWindowType type = widget->WindowType();
 
   LayoutDeviceIntRect curBounds = widget->GetClientBounds();
   bool invisiblePopup = type == eWindowType_popup &&
                         ((curBounds.IsEmpty() && mDimBounds.IsEmpty()) ||
                          mVis == nsViewVisibility_kHide);
 
@@ -355,17 +354,18 @@ void nsView::DoResetWidgetBounds(bool aM
   bool changedSize = curBounds.Size() != newBounds.Size();
 
   // Child views are never attached to top level widgets, this is safe.
 
   // 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).
-  DesktopToLayoutDeviceScale scale = dx->GetDesktopToDeviceScale();
+
+  DesktopToLayoutDeviceScale scale = widget->GetDesktopToDeviceScaleByScreen();
 
   DesktopRect deskRect = newBounds / scale;
   if (changedPos) {
     if (changedSize && !aMoveOnly) {
       widget->ResizeClient(deskRect.X(), deskRect.Y(),
                            deskRect.Width(), deskRect.Height(),
                            aInvalidateChangedSize);
     } else {
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -52,16 +52,17 @@
 #include <X11/extensions/shape.h>
 #include <gdk/gdkkeysyms-compat.h>
 #endif /* MOZ_X11 */
 
 #include <gdk/gdkkeysyms.h>
 
 #if defined(MOZ_WAYLAND)
 #include <gdk/gdkwayland.h>
+#include "nsView.h"
 #endif
 
 #include "nsGkAtoms.h"
 
 #ifdef MOZ_ENABLE_STARTUP_NOTIFICATION
 #define SN_API_NOT_YET_FROZEN
 #include <startup-notification-1.0/libsn/sn.h>
 #endif
@@ -836,16 +837,47 @@ nsWindow::GetDesktopToDeviceScale()
         return DesktopToLayoutDeviceScale(GdkScaleFactor());
     }
 #endif
 
     // In Gtk/X11, we manage windows using device pixels.
     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)
 {
     if (!mGdkWindow) {
         MOZ_ASSERT_UNREACHABLE("The native window has already been destroyed");
         return;
     }
 
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -120,16 +120,17 @@ public:
                                          nsNativeWidget aNativeParent,
                                          const LayoutDeviceIntRect& aRect,
                                          nsWidgetInitData* aInitData) override;
     virtual void       Destroy() override;
     virtual nsIWidget *GetParent() override;
     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;
     virtual void       ConstrainPosition(bool aAllowSlop,
                                          int32_t *aX,
                                          int32_t *aY) override;
     virtual void       SetSizeConstraints(const SizeConstraints& aConstraints) override;
     virtual void       Move(double aX, double aY) override;
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -79,16 +79,18 @@
 #include "FrameLayerBuilder.h"
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 #include "gfxConfig.h"
 #include "mozilla/layers/CompositorSession.h"
 #include "VRManagerChild.h"
 #include "gfxConfig.h"
+#include "nsView.h"
+#include "nsViewManager.h"
 
 #ifdef DEBUG
 #include "nsIObserver.h"
 
 static void debug_RegisterPrefCallbacks();
 
 #endif
 
@@ -2085,16 +2087,22 @@ nsBaseWidget::GetWidgetScreen()
   DesktopIntRect deskBounds = RoundedToInt(bounds / GetDesktopToDeviceScale());
   nsCOMPtr<nsIScreen> screen;
   screenManager->ScreenForRect(deskBounds.X(), deskBounds.Y(),
                                deskBounds.Width(), deskBounds.Height(),
                                getter_AddRefs(screen));
   return screen.forget();
 }
 
+mozilla::DesktopToLayoutDeviceScale
+nsBaseWidget::GetDesktopToDeviceScaleByScreen()
+{
+  return (nsView::GetViewFor(this)->GetViewManager()->GetDeviceContext())->GetDesktopToDeviceScale();
+}
+
 nsresult
 nsIWidget::SynthesizeNativeTouchTap(LayoutDeviceIntPoint aPoint, bool aLongTap,
                                     nsIObserver* aObserver)
 {
   AutoObserverNotifier notifier(aObserver, "touchtap");
 
   if (sPointerIdCounter > TOUCH_INJECT_MAX_POINTS) {
     sPointerIdCounter = 0;
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -19,16 +19,17 @@
 #include "nsIFile.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsIRollupListener.h"
 #include "nsIObserver.h"
 #include "nsIWidgetListener.h"
 #include "nsPIDOMWindow.h"
 #include "nsWeakReference.h"
+
 #include <algorithm>
 
 #if defined(XP_WIN)
 // Scroll capture constants
 const uint32_t kScrollCaptureFillColor = 0xFFa0a0a0; // gray
 const mozilla::gfx::SurfaceFormat kScrollCaptureFormat =
   mozilla::gfx::SurfaceFormat::X8R8G8B8_UINT32;
 #endif
@@ -233,16 +234,18 @@ public:
   bool                    BoundsUseDesktopPixels() const {
     return mWindowType <= eWindowType_popup;
   }
   // Default implementation, to be overridden by platforms where desktop coords
   // are virtualized and may not correspond to device pixels on the screen.
   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 {}
   virtual void            MoveClient(double aX, double aY) override;
   virtual void            ResizeClient(double aWidth, double aHeight, bool aRepaint) override;
   virtual void            ResizeClient(double aX, double aY, double aWidth, double aHeight, bool aRepaint) override;
   virtual LayoutDeviceIntRect GetBounds() override;
   virtual LayoutDeviceIntRect GetClientBounds() override;
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -573,16 +573,23 @@ class nsIWidget : public nsISupports
     /**
      * Return the scaling factor between device pixels and the platform-
      * dependent "desktop pixels" used to manage window positions on a
      * potentially multi-screen, mixed-resolution desktop.
      */
     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
      * depend on OS/platform settings such as the Mac's "UI scale factor"
      * or Windows' "font DPI". This will take into account Gecko preferences
      * overriding the system setting.
      */
     mozilla::CSSToLayoutDeviceScale GetDefaultScale();