Bug 1433068 - Titlebar/Linux - load and draw HiDPI titlebar icons on HiDPI screens, r?jhorak
MozReview-Commit-ID: KxbBvf6mgo1
--- a/widget/gtk/WidgetStyleCache.cpp
+++ b/widget/gtk/WidgetStyleCache.cpp
@@ -563,60 +563,79 @@ CreateHeaderBar(WidgetNodeType aWidgetTy
// at default Adwaita theme).
// We need to fix titlebar size calculation to also include
// titlebar button sizes. (Bug 1419442)
gtk_style_context_add_class(style, "default-decoration");
return headerbar;
}
+#define ICON_SCALE_VARIANTS 2
+
static void
LoadWidgetIconPixbuf(GtkWidget* aWidgetIcon)
{
GtkStyleContext* style = gtk_widget_get_style_context(aWidgetIcon);
const gchar *iconName;
GtkIconSize gtkIconSize;
gtk_image_get_icon_name(GTK_IMAGE(aWidgetIcon), &iconName, >kIconSize);
gint iconWidth, iconHeight;
gtk_icon_size_lookup(gtkIconSize, &iconWidth, &iconHeight);
- /* This is available since Gtk+ 3.10 as well as GtkHeaderBar */
+ /* Those are available since Gtk+ 3.10 as well as GtkHeaderBar */
static auto sGtkIconThemeLookupIconForScalePtr =
(GtkIconInfo* (*)(GtkIconTheme *, const gchar *, gint, gint, GtkIconLookupFlags))
dlsym(RTLD_DEFAULT, "gtk_icon_theme_lookup_icon_for_scale");
+ static auto sGdkCairoSurfaceCreateFromPixbufPtr =
+ (cairo_surface_t * (*)(const GdkPixbuf *, int, GdkWindow *))
+ dlsym(RTLD_DEFAULT, "gdk_cairo_surface_create_from_pixbuf");
- GtkIconInfo *gtkIconInfo =
- sGtkIconThemeLookupIconForScalePtr(gtk_icon_theme_get_default(),
- iconName,
- iconWidth,
- 1, /* TODO: scale for HiDPI */
- (GtkIconLookupFlags)0);
+ for (int scale = 1; scale < ICON_SCALE_VARIANTS+1; scale++) {
+ GtkIconInfo *gtkIconInfo =
+ sGtkIconThemeLookupIconForScalePtr(gtk_icon_theme_get_default(),
+ iconName,
+ iconWidth,
+ scale,
+ (GtkIconLookupFlags)0);
+
+ if (!gtkIconInfo) {
+ // We miss the icon, nothing to do here.
+ return;
+ }
- if (!gtkIconInfo) {
- // We miss the icon, nothing to do here.
- return;
- }
+ gboolean unused;
+ GdkPixbuf *iconPixbuf =
+ gtk_icon_info_load_symbolic_for_context(gtkIconInfo, style,
+ &unused, nullptr);
+ g_object_unref(G_OBJECT(gtkIconInfo));
- gboolean unused;
- GdkPixbuf *iconPixbuf =
- gtk_icon_info_load_symbolic_for_context(gtkIconInfo, style,
- &unused, nullptr);
- g_object_unref(G_OBJECT(gtkIconInfo));
+ cairo_surface_t* iconSurface =
+ sGdkCairoSurfaceCreateFromPixbufPtr(iconPixbuf, scale, nullptr);
+ g_object_unref(iconPixbuf);
- g_object_set_data_full(G_OBJECT(aWidgetIcon), "MozillaIconPixbuf", iconPixbuf,
- (GDestroyNotify)g_object_unref);
+ nsAutoCString surfaceName;
+ surfaceName = nsPrintfCString("MozillaIconSurface%d", scale);
+ g_object_set_data_full(G_OBJECT(aWidgetIcon), surfaceName.get(),
+ iconSurface,
+ (GDestroyNotify)cairo_surface_destroy);
+ }
}
-GdkPixbuf*
-GetWidgetIconPixbuf(GtkWidget* aWidgetIcon)
+cairo_surface_t*
+GetWidgetIconSurface(GtkWidget* aWidgetIcon, int aScale)
{
- return (GdkPixbuf*)g_object_get_data(G_OBJECT(aWidgetIcon),
- "MozillaIconPixbuf");
+ if (aScale > ICON_SCALE_VARIANTS)
+ aScale = ICON_SCALE_VARIANTS;
+
+ nsAutoCString surfaceName;
+ surfaceName = nsPrintfCString("MozillaIconSurface%d", aScale);
+ return (cairo_surface_t*)
+ g_object_get_data(G_OBJECT(aWidgetIcon), surfaceName.get());
}
// TODO - Also return style for buttons located at Maximized toolbar.
static GtkWidget*
CreateHeaderBarButton(WidgetNodeType aWidgetType)
{
MOZ_ASSERT(gtk_check_version(3, 10, 0) == nullptr,
"GtkHeaderBar is only available on GTK 3.10+.");
--- a/widget/gtk/WidgetStyleCache.h
+++ b/widget/gtk/WidgetStyleCache.h
@@ -16,18 +16,18 @@ typedef unsigned StyleFlags;
enum : StyleFlags {
NO_STYLE_FLAGS,
WHATEVER_MIGHT_BE_NEEDED = 1U << 0,
};
GtkWidget*
GetWidget(WidgetNodeType aNodeType);
-GdkPixbuf*
-GetWidgetIconPixbuf(GtkWidget* aWidgetIcon);
+cairo_surface_t*
+GetWidgetIconSurface(GtkWidget* aWidgetIcon, int aScale);
/*
* Return a new style context based on aWidget, as a child of aParentStyle.
* If aWidget still has a floating reference, then it is sunk and released.
*/
GtkStyleContext*
CreateStyleForWidget(GtkWidget* aWidget, GtkStyleContext* aParentStyle);
--- a/widget/gtk/gtk3drawing.cpp
+++ b/widget/gtk/gtk3drawing.cpp
@@ -13,16 +13,17 @@
#include <string.h>
#include "gtkdrawing.h"
#include "mozilla/Assertions.h"
#include "prinrval.h"
#include "WidgetStyleCache.h"
#include "nsDebug.h"
#include <math.h>
+#include <dlfcn.h>
static gboolean checkbox_check_state;
static gboolean notebook_has_tab_gap;
static ScrollbarGTKMetrics sScrollbarMetrics[2];
static ToggleGTKMetrics sCheckboxMetrics;
static ToggleGTKMetrics sRadioMetrics;
static ToolbarGTKMetrics sToolbarMetrics;
@@ -443,30 +444,35 @@ moz_gtk_header_bar_button_paint(cairo_t
WidgetNodeType aWidgetType,
GtkTextDirection direction)
{
GtkWidget *widget = GetWidget(aWidgetType);
InsetByMargin(rect, gtk_widget_get_style_context(widget));
moz_gtk_button_paint(cr, rect, state, relief, widget, direction);
GtkWidget* iconWidget = gtk_bin_get_child(GTK_BIN(widget));
- GdkPixbuf* pixbuf = GetWidgetIconPixbuf(iconWidget);
-
- if (pixbuf) {
+ cairo_surface_t *surface = GetWidgetIconSurface(iconWidget, state->scale);
+
+ if (surface) {
GtkStyleContext* style = gtk_widget_get_style_context(iconWidget);
GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
gtk_style_context_save(style);
gtk_style_context_set_state(style, state_flags);
const ToolbarButtonGTKMetrics *metrics =
GetToolbarButtonMetrics(aWidgetType);
- gtk_render_icon(style, cr, pixbuf,
- metrics->iconXPosition, metrics->iconYPosition);
+ /* This is available since Gtk+ 3.10 as well as GtkHeaderBar */
+ static auto sGtkRenderIconSurfacePtr =
+ (void (*)(GtkStyleContext *, cairo_t *, cairo_surface_t *, gdouble, gdouble))
+ dlsym(RTLD_DEFAULT, "gtk_render_icon_surface");
+
+ sGtkRenderIconSurfacePtr(style, cr, surface,
+ metrics->iconXPosition, metrics->iconYPosition);
gtk_style_context_restore(style);
}
return MOZ_GTK_SUCCESS;
}
static gint
moz_gtk_toggle_paint(cairo_t *cr, GdkRectangle* rect,
--- a/widget/gtk/gtkdrawing.h
+++ b/widget/gtk/gtkdrawing.h
@@ -27,16 +27,17 @@ typedef struct {
guint8 disabled;
guint8 isDefault;
guint8 canDefault;
/* The depressed state is for buttons which remain active for a longer period:
* activated toggle buttons or buttons showing a popup menu. */
guint8 depressed;
gint32 curpos; /* curpos and maxpos are used for scrollbars */
gint32 maxpos;
+ gint32 scale; /* actual widget scale */
} GtkWidgetState;
/**
* A size in the same GTK pixel units as GtkBorder and GdkRectangle.
*/
struct MozGtkSize {
gint width;
gint height;
--- a/widget/gtk/nsNativeThemeGTK.cpp
+++ b/widget/gtk/nsNativeThemeGTK.cpp
@@ -1121,16 +1121,20 @@ nsNativeThemeGTK::DrawWidgetBackground(g
Transparency transparency = GetWidgetTransparency(aFrame, aWidgetType);
// gdk rectangles are wrt the drawing rect.
GdkRectangle gdk_rect = {-drawingRect.x/scaleFactor,
-drawingRect.y/scaleFactor,
widgetRect.width/scaleFactor,
widgetRect.height/scaleFactor};
+ // Save actual widget scale to GtkWidgetState as we don't provide
+ // nsFrame to gtk3drawing routines.
+ state.scale = scaleFactor;
+
// translate everything so (0,0) is the top left of the drawingRect
gfxPoint origin = rect.TopLeft() + drawingRect.TopLeft();
DrawThemeWithCairo(ctx, aContext->GetDrawTarget(),
state, gtkWidgetType, flags, direction, scaleFactor,
snapped, ToPoint(origin), drawingRect.Size(),
gdk_rect, transparency);