Bug 1493081 - Added nsIWidget::GetDesktopToDeviceScaleByScreen for scale factor lookup by window position; r=mattwoodrow
☠☠ backed out by 5d7093d30ed3 ☠ ☠
authorJan Horak <jhorak@redhat.com>
Fri, 12 Oct 2018 17:03:54 +0000
changeset 501511 9a3a43e8743da65561b9ba4aa1f47777b6a61528
parent 500782 aa628ce24d80d9966a0bcdfce6bc0469da509c34
child 501512 6a8240b5c2871326cdbfa442741528bf213f7311
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1493081
milestone64.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/android/moz.build
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
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/android/moz.build
+++ b/widget/android/moz.build
@@ -33,26 +33,26 @@ EXPORTS += [
 
 EXPORTS.mozilla.widget += [
     'AndroidCompositorWidget.h',
     'AndroidUiThread.h',
 ]
 
 SOURCES += [
     '!GeneratedJNIWrappers.cpp',
+    'EventDispatcher.cpp',
 ]
 
 UNIFIED_SOURCES += [
     'AndroidAlerts.cpp',
     'AndroidBridge.cpp',
     'AndroidCompositorWidget.cpp',
     'AndroidContentController.cpp',
     'AndroidUiThread.cpp',
     'ANRReporter.cpp',
-    'EventDispatcher.cpp',
     'GeckoEditableSupport.cpp',
     'GfxInfo.cpp',
     'nsAndroidProtocolHandler.cpp',
     'nsAppShell.cpp',
     'nsClipboard.cpp',
     'nsDeviceContextAndroid.cpp',
     'nsIdleServiceAndroid.cpp',
     'nsLookAndFeel.cpp',
--- 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.h
+++ b/widget/nsBaseWidget.h
@@ -19,16 +19,18 @@
 #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 "nsView.h"
+#include "nsViewManager.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 +235,20 @@ 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 {
+    return (nsView::GetViewFor(this)->GetViewManager()->GetDeviceContext())->GetDesktopToDeviceScale();
+  }
+
   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();