Bug 1431337 - Scale content for the actual 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.
The GetSystemFontInfo() cannot return scaled value of the font by default monitor
scale factor. We need to scale it in nsLookAndFeel::GetFontImpl
by aDevPixPerCSSPixel like implementation for Windows does.
We also need to check layout.css.devPixelsPerPx because we cannot
scale per monitor when this preference is set to positive number.
MozReview-Commit-ID: AwT2NvkEqvz
--- a/widget/gtk/WindowSurfaceWayland.cpp
+++ b/widget/gtk/WindowSurfaceWayland.cpp
@@ -588,28 +588,40 @@ WindowSurfaceWayland::~WindowSurfaceWayl
NewRunnableFunction("WaylandDisplayRelease",
&WaylandDisplayRelease,
mWaylandDisplay->GetDisplay()));
} else {
WaylandDisplayRelease(mWaylandDisplay->GetDisplay());
}
}
+void
+WindowSurfaceWayland::UpdateScaleFactor()
+{
+ wl_surface* waylandSurface = mWindow->GetWaylandSurface();
+ if (waylandSurface) {
+ wl_surface_set_buffer_scale(waylandSurface, mWindow->GdkScaleFactor());
+ }
+}
+
WindowBackBuffer*
WindowSurfaceWayland::GetBufferToDraw(int aWidth, int aHeight)
{
if (!mFrontBuffer) {
mFrontBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
mBackBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
return mFrontBuffer;
}
if (!mFrontBuffer->IsAttached()) {
if (!mFrontBuffer->IsMatchingSize(aWidth, aHeight)) {
mFrontBuffer->Resize(aWidth, aHeight);
+ // There's a chance that scale factor has been changed
+ // when buffer size changed
+ UpdateScaleFactor();
}
return mFrontBuffer;
}
// Front buffer is used by compositor, draw to back buffer
if (mBackBuffer->IsAttached()) {
NS_WARNING("No drawing buffer available");
return nullptr;
@@ -696,20 +708,16 @@ WindowSurfaceWayland::Commit(const Layou
// Delete frame callback connected to obsoleted wl_surface.
wl_callback_destroy(mFrameCallback);
}
mFrameCallback = wl_surface_frame(waylandSurface);
wl_callback_add_listener(mFrameCallback, &frame_listener, this);
mFrameCallbackSurface = waylandSurface;
- // Let the wayland know of the current scaling factor for the hdpi
- // displays
- wl_surface_set_buffer_scale(waylandSurface, mWindow->GdkScaleFactor());
-
// There's no pending frame callback so we can draw immediately
// and create frame callback for possible subsequent drawing.
mFrontBuffer->Attach(waylandSurface);
mDelayedCommit = false;
}
}
void
--- a/widget/gtk/WindowSurfaceWayland.h
+++ b/widget/gtk/WindowSurfaceWayland.h
@@ -108,16 +108,17 @@ public:
~WindowSurfaceWayland();
already_AddRefed<gfx::DrawTarget> Lock(const LayoutDeviceIntRegion& aRegion) override;
void Commit(const LayoutDeviceIntRegion& aInvalidRegion) final override;
void FrameCallbackHandler();
private:
WindowBackBuffer* GetBufferToDraw(int aWidth, int aHeight);
+ void UpdateScaleFactor();
// TODO: Do we need to hold a reference to nsWindow object?
nsWindow* mWindow;
nsWaylandDisplay* mWaylandDisplay;
WindowBackBuffer* mFrontBuffer;
WindowBackBuffer* mBackBuffer;
wl_callback* mFrameCallback;
wl_surface* mFrameCallbackSurface;
--- a/widget/gtk/nsLookAndFeel.cpp
+++ b/widget/gtk/nsLookAndFeel.cpp
@@ -732,51 +732,47 @@ GetSystemFontInfo(GtkStyleContext *aStyl
float size = float(pango_font_description_get_size(desc)) / PANGO_SCALE;
// |size| is now either pixels or pango-points (not Mozilla-points!)
if (!pango_font_description_get_size_is_absolute(desc)) {
// |size| is in pango-points, so convert to pixels.
size *= float(gfxPlatformGtk::GetFontScaleDPI()) / POINTS_PER_INCH_FLOAT;
}
-
- // Scale fonts up on HiDPI displays.
- // This would be done automatically with cairo, but we manually manage
- // the display scale for platform consistency.
- size *= mozilla::widget::ScreenHelperGTK::GetGTKMonitorScaleFactor();
-
- // |size| is now pixels
+ // |size| is now pixels but not scaled for the hidpi displays,
+ // this needs to be done in GetFontImpl where the aDevPixPerCSSPixel
+ // parameter is provided.
aFontStyle->size = size;
pango_font_description_free(desc);
}
bool
nsLookAndFeel::GetFontImpl(FontID aID, nsString& aFontName,
gfxFontStyle& aFontStyle,
float aDevPixPerCSSPixel)
{
switch (aID) {
case eFont_Menu: // css2
case eFont_PullDownMenu: // css3
aFontName = mMenuFontName;
aFontStyle = mMenuFontStyle;
- return true;
+ break;
case eFont_Field: // css3
case eFont_List: // css3
aFontName = mFieldFontName;
aFontStyle = mFieldFontStyle;
- return true;
+ break;
case eFont_Button: // css3
aFontName = mButtonFontName;
aFontStyle = mButtonFontStyle;
- return true;
+ break;
case eFont_Caption: // css2
case eFont_Icon: // css2
case eFont_MessageBox: // css2
case eFont_SmallCaption: // css2
case eFont_StatusBar: // css2
case eFont_Window: // css3
case eFont_Document: // css3
@@ -784,18 +780,28 @@ nsLookAndFeel::GetFontImpl(FontID aID, n
case eFont_Desktop: // css3
case eFont_Info: // css3
case eFont_Dialog: // css3
case eFont_Tooltips: // moz
case eFont_Widget: // moz
default:
aFontName = mDefaultFontName;
aFontStyle = mDefaultFontStyle;
- return true;
+ break;
}
+ // Scale the font for the current monitor
+ double scaleFactor = nsIWidget::DefaultScaleOverride();
+ if (scaleFactor > 0) {
+ aFontStyle.size *= aDevPixPerCSSPixel;
+ } else {
+ // Remove effect of font scale because it has been already applied in
+ // GetSystemFontInfo
+ aFontStyle.size *= aDevPixPerCSSPixel / gfxPlatformGtk::GetFontScaleFactor();
+ }
+ return true;
}
void
nsLookAndFeel::EnsureInit()
{
GdkColor colorValue;
GdkColor *colorValuePtr;
--- 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,16 +55,39 @@ using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::widget;
NS_IMPL_ISUPPORTS_INHERITED(nsNativeThemeGTK, nsNativeTheme, nsITheme,
nsIObserver)
static int gLastGdkError;
+// Return scale factor of the monitor where the window is located
+// by the most part or layout.css.devPixelsPerPx pref if set to > 0.
+static inline gint
+GetMonitorScaleFactor(nsIFrame* aFrame)
+{
+ // When the layout.css.devPixelsPerPx is set the scale can be < 1,
+ // the real monitor scale cannot go under 1.
+ double scale = nsIWidget::DefaultScaleOverride();
+ if (scale <= 0) {
+ 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();
+ }
+ }
+ // We cannot return zero scale because that would lead to divide by zero
+ return (scale < 1) ? 1 : int(round(scale));
+}
+
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.
@@ -1040,17 +1064,17 @@ nsNativeThemeGTK::GetExtraSizeForWidget(
} else {
aExtra->bottom = extra;
}
return false;
}
default:
return false;
}
- gint scale = ScreenHelperGTK::GetGTKMonitorScaleFactor();
+ gint scale = GetMonitorScaleFactor(aFrame);
aExtra->top *= scale;
aExtra->right *= scale;
aExtra->bottom *= scale;
aExtra->left *= scale;
return true;
}
NS_IMETHODIMP
@@ -1068,17 +1092,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);
// 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.
@@ -1314,17 +1338,17 @@ nsNativeThemeGTK::GetWidgetBorder(nsDevi
break;
MOZ_FALLTHROUGH;
default:
{
GetCachedWidgetBorder(aFrame, aWidgetType, direction, aResult);
}
}
- gint scale = ScreenHelperGTK::GetGTKMonitorScaleFactor();
+ gint scale = GetMonitorScaleFactor(aFrame);
aResult->top *= scale;
aResult->right *= scale;
aResult->bottom *= scale;
aResult->left *= scale;
return NS_OK;
}
bool
@@ -1372,17 +1396,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);
aResult->top *= scale;
aResult->right *= scale;
aResult->bottom *= scale;
aResult->left *= scale;
return true;
}
}
@@ -1621,18 +1645,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:
{
@@ -1674,17 +1697,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);
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
@@ -71,17 +71,16 @@ 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;
-
nsNativeThemeGTK();
protected:
virtual ~nsNativeThemeGTK();
private:
GtkTextDirection GetTextDirection(nsIFrame* aFrame);
gint GetTabMarginPixels(nsIFrame* aFrame);
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -5926,16 +5926,17 @@ widget_composited_changed_cb (GtkWidget*
static void
scale_changed_cb (GtkWidget* widget, GParamSpec* aPSpec, gpointer aPointer)
{
RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
if (!window) {
return;
}
+ // This eventually propagate new scale to the PuppetWidgets
window->OnDPIChanged();
// configure_event is already fired before scale-factor signal,
// but size-allocate isn't fired by changing scale
GtkAllocation allocation;
gtk_widget_get_allocation(widget, &allocation);
window->OnSizeAllocate(&allocation);
}