Bug 1431337 Scale widget size to the current monitor, not the first one; r?stransky draft
authorJan Horak <jhorak@redhat.com>
Thu, 18 Jan 2018 11:52:59 +0100
changeset 748789 919adbd1119c1de470d411d5c6b76dfc4c0c6b2d
parent 722085 43fa1ba322d73122e66632cfdfdc8edb8e53e32e
push id97232
push userbmo:jhorak@redhat.com
push dateTue, 30 Jan 2018 11:41:26 +0000
reviewersstransky
bugs1431337
milestone59.0a1
Bug 1431337 Scale widget size to the current monitor, not the first one; r?stransky We need to use scaling factor of the monitor on which application is actually positioned. Previously we used ScreenHelperGTK::GetGTKMonitorScaleFactor() which use the first monitor. This does not work on hidpi+normal dpi monitors setup. We also need to listen to the changes of layout.css.devPixelsPerPx because we cannot scale per monitor when this preference is set to positive number. MozReview-Commit-ID: 4y1Dv5DWiNX
widget/gtk/nsNativeThemeGTK.cpp
widget/gtk/nsNativeThemeGTK.h
--- a/widget/gtk/nsNativeThemeGTK.cpp
+++ b/widget/gtk/nsNativeThemeGTK.cpp
@@ -32,16 +32,17 @@
 #include <gtk/gtkx.h>
 
 #include "gfxContext.h"
 #include "gfxPlatformGtk.h"
 #include "gfxGdkNativeRenderer.h"
 #include "mozilla/gfx/BorrowedContext.h"
 #include "mozilla/gfx/HelpersCairo.h"
 #include "mozilla/gfx/PathHelpers.h"
+#include "mozilla/Preferences.h"
 
 #ifdef MOZ_X11
 #  ifdef CAIRO_HAS_XLIB_SURFACE
 #    include "cairo-xlib.h"
 #  endif
 #  ifdef CAIRO_HAS_XLIB_XRENDER_SURFACE
 #    include "cairo-xlib-xrender.h"
 #  endif
@@ -54,32 +55,67 @@ using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::widget;
 
 NS_IMPL_ISUPPORTS_INHERITED(nsNativeThemeGTK, nsNativeTheme, nsITheme,
                                                              nsIObserver)
 
 static int gLastGdkError;
 
+static void UpdateDevPixelsPerPxCB(const char*, void* aClosure)
+{
+  static_cast<nsNativeThemeGTK*>(aClosure)->UpdateDevPixelsPerPx();
+}
+// Return scale factor of the monitor where the window is located
+// by the most part.
+static inline gint
+GetMonitorScaleFactor(nsIFrame* aFrame, double aDevPixelsPerPx)
+{
+  // When the layout.css.devPixelsPerPx is set the scale can be < 1,
+  // the real monitor scale cannot go under 1.
+  if (aDevPixelsPerPx > 0) {
+    return 1;
+  }
+
+  nsIWidget* rootWidget = aFrame->PresContext()->GetRootWidget();
+  if (rootWidget) {
+      // We need to use GetDefaultScale() despite it returns monitor scale
+      // factor multiplied by font scale factor because it is the only scale
+      // updated in nsPuppetWidget.
+      // Since we don't want to apply font scale factor for UI elements
+      // (because GTK does not do so) we need to remove that from returned value.
+      return rootWidget->GetDefaultScale().scale / gfxPlatformGtk::GetFontScaleFactor();
+  }
+  return 1.0;
+}
+
+NS_IMETHODIMP
+nsNativeThemeGTK::UpdateDevPixelsPerPx()
+{
+  mDevPixelsPerPx = Preferences::GetFloat("layout.css.devPixelsPerPx", -1);
+  return NS_OK;
+}
+
 nsNativeThemeGTK::nsNativeThemeGTK()
 {
   if (moz_gtk_init() != MOZ_GTK_SUCCESS) {
     memset(mDisabledWidgetTypes, 0xff, sizeof(mDisabledWidgetTypes));
     return;
   }
 
   // We have to call moz_gtk_shutdown before the event loop stops running.
   nsCOMPtr<nsIObserverService> obsServ =
     mozilla::services::GetObserverService();
   obsServ->AddObserver(this, "xpcom-shutdown", false);
-
+  Preferences::RegisterCallback(UpdateDevPixelsPerPxCB, "layout.css.devPixelsPerPx", this);
   ThemeChanged();
 }
 
 nsNativeThemeGTK::~nsNativeThemeGTK() {
+  Preferences::UnregisterCallback(UpdateDevPixelsPerPxCB, "layout.css.devPixelsPerPx", this);
 }
 
 NS_IMETHODIMP
 nsNativeThemeGTK::Observe(nsISupports *aSubject, const char *aTopic,
                           const char16_t *aData)
 {
   if (!nsCRT::strcmp(aTopic, "xpcom-shutdown")) {
     moz_gtk_shutdown();
@@ -1040,17 +1076,17 @@ nsNativeThemeGTK::GetExtraSizeForWidget(
       } else {
         aExtra->bottom = extra;
       }
       return false;
     }
   default:
     return false;
   }
-  gint scale = ScreenHelperGTK::GetGTKMonitorScaleFactor();
+  gint scale = GetMonitorScaleFactor(aFrame, mDevPixelsPerPx);
   aExtra->top *= scale;
   aExtra->right *= scale;
   aExtra->bottom *= scale;
   aExtra->left *= scale;
   return true;
 }
 
 NS_IMETHODIMP
@@ -1068,17 +1104,17 @@ nsNativeThemeGTK::DrawWidgetBackground(g
                             &flags))
     return NS_OK;
 
   gfxContext* ctx = aContext;
   nsPresContext *presContext = aFrame->PresContext();
 
   gfxRect rect = presContext->AppUnitsToGfxUnits(aRect);
   gfxRect dirtyRect = presContext->AppUnitsToGfxUnits(aDirtyRect);
-  gint scaleFactor = ScreenHelperGTK::GetGTKMonitorScaleFactor();
+  gint scaleFactor = GetMonitorScaleFactor(aFrame, mDevPixelsPerPx);
 
   // Align to device pixels where sensible
   // to provide crisper and faster drawing.
   // Don't snap if it's a non-unit scale factor. We're going to have to take
   // slow paths then in any case.
   bool snapped = ctx->UserToDevicePixelSnapped(rect);
   if (snapped) {
     // Leave rect in device coords but make dirtyRect consistent.
@@ -1287,17 +1323,17 @@ nsNativeThemeGTK::GetWidgetBorder(nsDevi
       break;
     MOZ_FALLTHROUGH;
   default:
     {
       GetCachedWidgetBorder(aFrame, aWidgetType, direction, aResult);
     }
   }
 
-  gint scale = ScreenHelperGTK::GetGTKMonitorScaleFactor();
+  gint scale = GetMonitorScaleFactor(aFrame, mDevPixelsPerPx);
   aResult->top *= scale;
   aResult->right *= scale;
   aResult->bottom *= scale;
   aResult->left *= scale;
   return NS_OK;
 }
 
 bool
@@ -1345,17 +1381,17 @@ nsNativeThemeGTK::GetWidgetPadding(nsDev
         if (aWidgetType == NS_THEME_MENUITEM)
           moz_gtk_menuitem_get_horizontal_padding(&horizontal_padding);
         else
           moz_gtk_checkmenuitem_get_horizontal_padding(&horizontal_padding);
 
         aResult->left += horizontal_padding;
         aResult->right += horizontal_padding;
 
-        gint scale = ScreenHelperGTK::GetGTKMonitorScaleFactor();
+        gint scale = GetMonitorScaleFactor(aFrame, mDevPixelsPerPx);
         aResult->top *= scale;
         aResult->right *= scale;
         aResult->bottom *= scale;
         aResult->left *= scale;
 
         return true;
       }
   }
@@ -1566,18 +1602,17 @@ nsNativeThemeGTK::GetMinimumWidgetSize(n
         moz_gtk_get_arrow_size(MOZ_GTK_DROPDOWN,
                                &aResult->width, &aResult->height);
       }
       // else the minimum size is missing consideration of container
       // descendants; the value returned here will not be helpful, but the
       // box model may consider border and padding with child minimum sizes.
 
       nsIntMargin border;
-      nsNativeThemeGTK::GetWidgetBorder(aFrame->PresContext()->DeviceContext(),
-                                        aFrame, aWidgetType, &border);
+      GetCachedWidgetBorder(aFrame, aWidgetType, GetTextDirection(aFrame), &border);
       aResult->width += border.left + border.right;
       aResult->height += border.top + border.bottom;
     }
     break;
 #ifdef MOZ_WIDGET_GTK
   case NS_THEME_NUMBER_INPUT:
   case NS_THEME_TEXTFIELD:
     {
@@ -1619,17 +1654,17 @@ nsNativeThemeGTK::GetMinimumWidgetSize(n
 
       moz_gtk_get_treeview_expander_size(&expander_size);
       aResult->width = aResult->height = expander_size;
       *aIsOverridable = false;
     }
     break;
   }
 
-  *aResult = *aResult * ScreenHelperGTK::GetGTKMonitorScaleFactor();
+  *aResult = *aResult * GetMonitorScaleFactor(aFrame, mDevPixelsPerPx);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNativeThemeGTK::WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType,
                                      nsAtom* aAttribute, bool* aShouldRepaint,
                                      const nsAttrValue* aOldValue)
--- a/widget/gtk/nsNativeThemeGTK.h
+++ b/widget/gtk/nsNativeThemeGTK.h
@@ -63,17 +63,17 @@ public:
   NS_IMETHOD_(bool) WidgetIsContainer(uint8_t aWidgetType) override;
 
   NS_IMETHOD_(bool) ThemeDrawsFocusForWidget(uint8_t aWidgetType) override;
 
   virtual bool ThemeNeedsComboboxDropmarker() override;
 
   virtual Transparency GetWidgetTransparency(nsIFrame* aFrame,
                                              uint8_t aWidgetType) override;
-
+  NS_IMETHOD UpdateDevPixelsPerPx();
   nsNativeThemeGTK();
 
 protected:
   virtual ~nsNativeThemeGTK();
 
 private:
   GtkTextDirection GetTextDirection(nsIFrame* aFrame);
   gint GetTabMarginPixels(nsIFrame* aFrame);
@@ -92,11 +92,12 @@ private:
 
   // Because moz_gtk_get_widget_border can be slow, we cache its results
   // by widget type.  Each bit in mBorderCacheValid says whether the
   // corresponding entry in mBorderCache is valid.
   void GetCachedWidgetBorder(nsIFrame* aFrame, uint8_t aWidgetType,
                              GtkTextDirection aDirection, nsIntMargin* aResult);
   uint8_t mBorderCacheValid[(MOZ_GTK_WIDGET_NODE_COUNT + 7) / 8];
   nsIntMargin mBorderCache[MOZ_GTK_WIDGET_NODE_COUNT];
+  double mDevPixelsPerPx;
 };
 
 #endif