IconTheme: Simplify icon scaling

We had a pretty complex setup where we tried to avoid scaling up themes from dirs
that specified a size. However, not only was it very complex, but it didn't quite
work with window scales, because when using e.g. a size 32 directory for 16@2x
the dir size is wrong anyway. Additionally it turns out most code either picks
an existing icon size, or uses the FORCE_SIZE flags, so it doesn't seem
like a useful behaviour.

This change drops the FORCE_SIZE flags, and always scales
icons. Additionally it moves the scaling of the icon to rendering,
which seems more modern, and allows us to (later) share icons loaded
for different sizes that happened to use the same source file (at
different scales).

Note that this changes the behaviour of
gtk_icon_paintable_download_texture() is it now returns the unscaled
source icon. However, ignore thats, as I plan to remove this function
and replace it with a way to render a paintable to a cairo-surface
instead.
This commit is contained in:
Alexander Larsson 2020-02-05 15:47:23 +01:00
parent 021aaef824
commit b529f77827
9 changed files with 208 additions and 387 deletions

View File

@ -49,7 +49,9 @@ struct _IconBrowserWindow
GtkWidget *image4;
GtkWidget *image5;
GtkWidget *image6;
GtkWidget *label6;
GtkWidget *image7;
GtkWidget *image8;
GtkWidget *label8;
GtkWidget *description;
};
@ -113,21 +115,23 @@ item_activated (GtkIconView *icon_view, GtkTreePath *path, IconBrowserWindow *wi
}
gtk_window_set_title (GTK_WINDOW (win->details), name);
set_image (win->image1, name, 16);
set_image (win->image2, name, 24);
set_image (win->image3, name, 32);
set_image (win->image4, name, 48);
set_image (win->image5, name, 64);
set_image (win->image1, name, 8);
set_image (win->image2, name, 16);
set_image (win->image3, name, 18);
set_image (win->image4, name, 24);
set_image (win->image5, name, 32);
set_image (win->image6, name, 48);
set_image (win->image7, name, 64);
if (win->symbolic)
{
gtk_widget_show (win->image6);
gtk_widget_show (win->label6);
set_image (win->image6, name, 64);
gtk_widget_show (win->image8);
gtk_widget_show (win->label8);
set_image (win->image8, name, 64);
}
else
{
gtk_widget_hide (win->image6);
gtk_widget_hide (win->label6);
gtk_widget_hide (win->image8);
gtk_widget_hide (win->label8);
}
if (description && description[0])
{
@ -372,7 +376,7 @@ get_image_paintable (GtkImage *image)
NULL,
size, 1,
gtk_widget_get_direction (GTK_WIDGET (image)),
GTK_ICON_LOOKUP_FORCE_SIZE);
0);
if (icon == NULL)
return NULL;
return GDK_PAINTABLE (icon);
@ -484,7 +488,9 @@ icon_browser_window_init (IconBrowserWindow *win)
setup_image_dnd (win->image3);
setup_image_dnd (win->image4);
setup_image_dnd (win->image5);
setup_scalable_image_dnd (win->image6);
setup_image_dnd (win->image6);
setup_image_dnd (win->image7);
setup_scalable_image_dnd (win->image8);
win->contexts = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, context_free);
@ -541,7 +547,9 @@ icon_browser_window_class_init (IconBrowserWindowClass *class)
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, image4);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, image5);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, image6);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, label6);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, image7);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, image8);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, label8);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, description);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), search_text_changed);

View File

@ -198,7 +198,7 @@
<property name="halign">center</property>
<property name="valign">end</property>
<accessibility>
<relation type="labelled-by" target="label6"/>
<relation type="labelled-by" target="label5"/>
</accessibility>
<layout>
<property name="left-attach">5</property>
@ -206,11 +206,37 @@
</layout>
</object>
</child>
<child>
<object class="GtkImage" id="image7">
<property name="halign">center</property>
<property name="valign">end</property>
<accessibility>
<relation type="labelled-by" target="label5"/>
</accessibility>
<layout>
<property name="left-attach">6</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkImage" id="image8">
<property name="halign">center</property>
<property name="valign">end</property>
<accessibility>
<relation type="labelled-by" target="label6"/>
</accessibility>
<layout>
<property name="left-attach">7</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="halign">center</property>
<property name="valign">baseline</property>
<property name="label">16×16</property>
<property name="label">8×8</property>
<style>
<class name="dim-label"/>
</style>
@ -227,7 +253,7 @@
<object class="GtkLabel" id="label2">
<property name="halign">center</property>
<property name="valign">baseline</property>
<property name="label">24×24</property>
<property name="label">16×16</property>
<style>
<class name="dim-label"/>
</style>
@ -244,7 +270,7 @@
<object class="GtkLabel" id="label3">
<property name="halign">center</property>
<property name="valign">baseline</property>
<property name="label">32×32</property>
<property name="label">18×18</property>
<style>
<class name="dim-label"/>
</style>
@ -261,7 +287,7 @@
<object class="GtkLabel" id="label4">
<property name="halign">center</property>
<property name="valign">baseline</property>
<property name="label">48×48</property>
<property name="label">24×24</property>
<style>
<class name="dim-label"/>
</style>
@ -278,7 +304,7 @@
<object class="GtkLabel" id="label5">
<property name="halign">center</property>
<property name="valign">baseline</property>
<property name="label">64×64</property>
<property name="label">32×32</property>
<style>
<class name="dim-label"/>
</style>
@ -295,7 +321,7 @@
<object class="GtkLabel" id="label6">
<property name="halign">center</property>
<property name="valign">baseline</property>
<property name="label">scalable</property>
<property name="label">48×48</property>
<style>
<class name="dim-label"/>
</style>
@ -308,6 +334,40 @@
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="label7">
<property name="halign">center</property>
<property name="valign">baseline</property>
<property name="label">64×64</property>
<style>
<class name="dim-label"/>
</style>
<accessibility>
<relation type="label-for" target="image7"/>
</accessibility>
<layout>
<property name="left-attach">6</property>
<property name="top-attach">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="label8">
<property name="halign">center</property>
<property name="valign">baseline</property>
<property name="label">scalable</property>
<style>
<class name="dim-label"/>
</style>
<accessibility>
<relation type="label-for" target="image8"/>
</accessibility>
<layout>
<property name="left-attach">7</property>
<property name="top-attach">2</property>
</layout>
</object>
</child>
</object>
</child>
<child>

View File

@ -403,7 +403,6 @@ create_icon_helper (GtkCellRendererPixbuf *cellpixbuf,
icon_helper = gtk_icon_helper_new (gtk_style_context_get_node (gtk_widget_get_style_context (widget)),
widget);
_gtk_icon_helper_set_use_fallback (icon_helper, TRUE);
_gtk_icon_helper_set_force_scale_pixbuf (icon_helper, TRUE);
_gtk_icon_helper_set_definition (icon_helper, priv->image_def);
return icon_helper;

View File

@ -46,7 +46,6 @@ struct _GtkIconHelper
gint pixel_size;
guint use_fallback : 1;
guint force_scale_pixbuf : 1;
guint texture_is_symbolic : 1;
GtkWidget *owner;
@ -63,9 +62,6 @@ get_icon_lookup_flags (GtkIconHelper *self,
flags = 0;
if (self->pixel_size != -1 || self->force_scale_pixbuf)
flags |= GTK_ICON_LOOKUP_FORCE_SIZE;
icon_style = _gtk_css_icon_style_value_get (style->icon->icon_style);
switch (icon_style)
@ -567,23 +563,6 @@ _gtk_icon_helper_get_is_empty (GtkIconHelper *self)
return gtk_image_definition_get_storage_type (self->def) == GTK_IMAGE_EMPTY;
}
gboolean
_gtk_icon_helper_get_force_scale_pixbuf (GtkIconHelper *self)
{
return self->force_scale_pixbuf;
}
void
_gtk_icon_helper_set_force_scale_pixbuf (GtkIconHelper *self,
gboolean force_scale)
{
if (self->force_scale_pixbuf != force_scale)
{
self->force_scale_pixbuf = force_scale;
gtk_icon_helper_invalidate (self);
}
}
void
gtk_icon_size_set_style_classes (GtkCssNode *cssnode,
GtkIconSize icon_size)

View File

@ -66,10 +66,6 @@ const gchar *_gtk_icon_helper_get_icon_name (GtkIconHelper *self);
int gtk_icon_helper_get_size (GtkIconHelper *self);
gboolean _gtk_icon_helper_get_force_scale_pixbuf (GtkIconHelper *self);
void _gtk_icon_helper_set_force_scale_pixbuf (GtkIconHelper *self,
gboolean force_scale);
void gtk_icon_helper_invalidate (GtkIconHelper *self);
void gtk_icon_helper_invalidate_for_change (GtkIconHelper *self,
GtkCssStyleChange *change);

View File

@ -273,26 +273,13 @@ struct _GtkIconPaintable
/* Cache pixbuf (if there is any) */
GdkPixbuf *cache_pixbuf;
/* Information about the directory where
* the source was found
*/
IconThemeDirType dir_type;
gint dir_size;
gint dir_scale;
gint min_size;
gint max_size;
/* Parameters influencing the scaled icon
*/
gint desired_size;
gint desired_scale;
gint rendered_size;
gdouble unscaled_scale;
guint forced_size : 1;
guint is_svg : 1;
guint is_resource : 1;
/* Cached information if we go ahead and try to load the icon.
*
* All access to these are protected by the texture_lock. Everything
@ -303,9 +290,6 @@ struct _GtkIconPaintable
GdkTexture *texture;
GError *load_error;
gdouble scale;
gint symbolic_width;
gint symbolic_height;
};
typedef struct
@ -360,40 +344,39 @@ typedef struct
gboolean exists;
} IconThemeDirMtime;
static void gtk_icon_theme_finalize (GObject *object);
static void gtk_icon_theme_dispose (GObject *object);
static IconTheme * theme_new (const char *theme_name,
GKeyFile *theme_file);
static void theme_dir_size_destroy (IconThemeDirSize *dir_size);
static void theme_dir_destroy (IconThemeDir *dir);
static void theme_destroy (IconTheme *theme);
static GtkIconPaintable *theme_lookup_icon (IconTheme *theme,
const gchar *icon_name,
gint size,
gint scale,
gboolean allow_svg);
static void theme_list_icons (IconTheme *theme,
GHashTable *icons);
static gboolean theme_has_icon (IconTheme *theme,
const gchar *icon_name);
static void theme_subdir_load (GtkIconTheme *self,
IconTheme *theme,
GKeyFile *theme_file,
gchar *subdir);
static void do_theme_change (GtkIconTheme *self);
static void blow_themes (GtkIconTheme *self);
static gboolean rescan_themes (GtkIconTheme *self);
static GtkIconPaintable *icon_paintable_new (IconThemeDirType type,
gint dir_size,
gint dir_scale);
static void icon_compute_rendered_size (GtkIconPaintable *icon);
static IconCacheFlag suffix_from_name (const gchar *name);
static gboolean icon_ensure_scale_and_texture__locked (GtkIconPaintable *icon,
gboolean in_thread);
static void unset_display (GtkIconTheme *self);
static void update_current_theme__mainthread (GtkIconTheme *self);
static gboolean ensure_valid_themes (GtkIconTheme *self,
gboolean non_blocking);
static void gtk_icon_theme_finalize (GObject *object);
static void gtk_icon_theme_dispose (GObject *object);
static IconTheme * theme_new (const char *theme_name,
GKeyFile *theme_file);
static void theme_dir_size_destroy (IconThemeDirSize *dir_size);
static void theme_dir_destroy (IconThemeDir *dir);
static void theme_destroy (IconTheme *theme);
static GtkIconPaintable *theme_lookup_icon (IconTheme *theme,
const gchar *icon_name,
gint size,
gint scale,
gboolean allow_svg);
static void theme_list_icons (IconTheme *theme,
GHashTable *icons);
static gboolean theme_has_icon (IconTheme *theme,
const gchar *icon_name);
static void theme_subdir_load (GtkIconTheme *self,
IconTheme *theme,
GKeyFile *theme_file,
gchar *subdir);
static void do_theme_change (GtkIconTheme *self);
static void blow_themes (GtkIconTheme *self);
static gboolean rescan_themes (GtkIconTheme *self);
static GtkIconPaintable *icon_paintable_new (int desired_size,
int desired_scale);
static IconCacheFlag suffix_from_name (const gchar *name);
static gboolean icon_ensure_texture__locked (GtkIconPaintable *icon,
gboolean in_thread);
static void unset_display (GtkIconTheme *self);
static void update_current_theme__mainthread (GtkIconTheme *self);
static gboolean ensure_valid_themes (GtkIconTheme *self,
gboolean non_blocking);
static guint signal_changed = 0;
@ -1811,7 +1794,6 @@ real_choose_icon (GtkIconTheme *self,
{
GList *l;
GtkIconPaintable *icon = NULL;
GtkIconPaintable *unscaled_icon;
UnthemedIcon *unthemed_icon = NULL;
const gchar *icon_name = NULL;
IconTheme *theme = NULL;
@ -1896,7 +1878,7 @@ real_choose_icon (GtkIconTheme *self,
if (hIcon)
{
icon = icon_paintable_new (ICON_THEME_DIR_UNTHEMED, size, 1);
icon = icon_paintable_new (size, scale);
icon->cache_pixbuf = gdk_win32_icon_to_pixbuf_libgtk_only (hIcon, NULL, NULL);
DestroyIcon (hIcon);
}
@ -1906,7 +1888,7 @@ real_choose_icon (GtkIconTheme *self,
if (unthemed_icon)
{
icon = icon_paintable_new (ICON_THEME_DIR_UNTHEMED, size, 1);
icon = icon_paintable_new (size, scale);
/* A SVG icon, when allowed, beats out a XPM icon, but not a PNG icon */
if (self->pixbuf_supports_svg &&
@ -1940,25 +1922,6 @@ real_choose_icon (GtkIconTheme *self,
{
icon->desired_size = size;
icon->desired_scale = scale;
icon->forced_size = (flags & GTK_ICON_LOOKUP_FORCE_SIZE) != 0;
/* In case we're not scaling the icon we want to reuse the exact same
* size as a scale==1 lookup would be, rather than not scaling at all
* and causing a different layout
*/
icon->unscaled_scale = 1.0;
if (scale != 1 && !icon->forced_size && theme != NULL)
{
unscaled_icon = theme_lookup_icon (theme, icon_name, size, 1, self->pixbuf_supports_svg);
if (unscaled_icon)
{
icon->unscaled_scale =
(gdouble) unscaled_icon->dir_size * scale / (icon->dir_size * icon->dir_scale);
g_object_unref (unscaled_icon);
}
}
icon_compute_rendered_size (icon);
icon->key.icon_names = g_strdupv ((char **)icon_names);
icon->key.size = size;
@ -2140,7 +2103,7 @@ choose_icon (GtkIconTheme *self,
* @self: a #GtkIconTheme
* @icon_name: the name of the icon to lookup
* @fallbacks: (nullable) (array zero-terminated=1):
* @size: desired icon size. The resulting icon may not be exactly this size.
* @size: desired icon size.
* @scale: the window scale this will be displayed on
* @direction: text direction the icon will be displayed in
* @flags: flags modifying the behavior of the icon lookup
@ -2150,15 +2113,6 @@ choose_icon (GtkIconTheme *self,
* or you can get information such as the filename and size. The pixels
* of the texture can be access by using gtk_icon_paintable_download_texture().
*
* The icon icon size will be based on the requested @size, but may
* not be exactly this size; an icon theme may have icons that differ
* slightly from their nominal sizes, and in addition GTK+ will avoid
* scaling icons that it considers sufficiently close to the requested
* size or for which the source image would have to be scaled up too
* far. (This maintains sharpness.). This behaviour can be changed by
* passing the %GTK_ICON_LOOKUP_FORCE_SIZE flag, which causes the icon
* to be scaled to the exact size.
*
* If the available @icon_name is not available and @fallbacks are provided,
* they will be tried in order.
*
@ -2763,9 +2717,7 @@ theme_lookup_icon (IconTheme *theme,
IconThemeDir *dir = &g_array_index (theme->dirs, IconThemeDir, min_file->dir_index);
gchar *filename;
icon = icon_paintable_new (min_dir_size->type, min_dir_size->size, min_dir_size->scale);
icon->min_size = min_dir_size->min_size;
icon->max_size = min_dir_size->max_size;
icon = icon_paintable_new (size, scale);
filename = g_strconcat (icon_name, string_from_suffix (min_suffix), NULL);
icon->filename = g_build_filename (dir->path, filename, NULL);
@ -3147,69 +3099,23 @@ G_DEFINE_TYPE_WITH_CODE (GtkIconPaintable, gtk_icon_paintable, G_TYPE_OBJECT,
static void
gtk_icon_paintable_init (GtkIconPaintable *icon)
{
icon->scale = -1.;
g_mutex_init (&icon->texture_lock);
}
static GtkIconPaintable *
icon_paintable_new (IconThemeDirType type,
gint dir_size,
gint dir_scale)
icon_paintable_new (int desired_size,
int desired_scale)
{
GtkIconPaintable *icon;
icon = g_object_new (GTK_TYPE_ICON_PAINTABLE, NULL);
icon->dir_type = type;
icon->dir_size = dir_size;
icon->dir_scale = dir_scale;
icon->unscaled_scale = 1.0;
icon->is_svg = FALSE;
icon->is_resource = FALSE;
icon->rendered_size = -1;
icon->desired_size = desired_size;
icon->desired_scale = desired_scale;
return icon;
}
static void
icon_compute_rendered_size (GtkIconPaintable *icon)
{
int rendered_size;
if (icon->forced_size ||
icon->dir_type == ICON_THEME_DIR_UNTHEMED)
{
rendered_size = icon->desired_size;
}
else if (icon->dir_type == ICON_THEME_DIR_FIXED ||
icon->dir_type == ICON_THEME_DIR_THRESHOLD)
{
rendered_size = icon->dir_size * icon->dir_scale * icon->unscaled_scale / icon->desired_scale;
}
else /* Scalable */
{
gdouble dir_scale = icon->dir_scale;
gint scaled_desired_size;
scaled_desired_size = icon->desired_size * icon->desired_scale;
/* See icon_ensure_scale_and_texture() comment for why we do this */
if (icon->is_svg)
dir_scale = icon->desired_scale;
if (scaled_desired_size < icon->min_size * dir_scale)
rendered_size = icon->min_size * dir_scale;
else if (scaled_desired_size > icon->max_size * dir_scale)
rendered_size = icon->max_size * dir_scale;
else
rendered_size = scaled_desired_size;
rendered_size /= icon->desired_scale;
}
icon->rendered_size = rendered_size;
}
static void
gtk_icon_paintable_finalize (GObject *object)
{
@ -3305,14 +3211,12 @@ icon_get_loadable (GtkIconPaintable *icon)
* that size.
*/
static gboolean
icon_ensure_scale_and_texture__locked (GtkIconPaintable *icon,
gboolean in_thread)
icon_ensure_texture__locked (GtkIconPaintable *icon,
gboolean in_thread)
{
gint image_width, image_height, image_size;
gint scaled_desired_size;
GdkPixbuf *source_pixbuf;
gdouble dir_scale;
gint64 before;
gint pixel_size;
icon_cache_mark_used_if_cached (icon);
@ -3324,38 +3228,10 @@ icon_ensure_scale_and_texture__locked (GtkIconPaintable *icon,
before = g_get_monotonic_time ();
scaled_desired_size = icon->desired_size * icon->desired_scale;
dir_scale = icon->dir_scale;
/* In many cases, the scale can be determined without actual access
* to the icon file. This is generally true when we have a size
* for the directory where the icon is; the image size doesn't
* matter in that case.
/* This is the natural pixel size for the requested icon size + scale in this directory.
* We precalculate this so we can use it as a rasterization size for svgs.
*/
if (icon->forced_size ||
icon->dir_type == ICON_THEME_DIR_UNTHEMED)
icon->scale = -1;
else if (icon->dir_type == ICON_THEME_DIR_FIXED ||
icon->dir_type == ICON_THEME_DIR_THRESHOLD)
icon->scale = icon->unscaled_scale;
else if (icon->dir_type == ICON_THEME_DIR_SCALABLE)
{
/* For svg icons, treat scalable directories as if they had
* a Scale=<desired_scale> entry. In particular, this means
* spinners that are restriced to size 32 will loaded at size
* up to 64 with Scale=2.
*/
if (icon->is_svg)
dir_scale = icon->desired_scale;
if (scaled_desired_size < icon->min_size * dir_scale)
icon->scale = (gdouble) icon->min_size / (gdouble) icon->dir_size;
else if (scaled_desired_size > icon->max_size * dir_scale)
icon->scale = (gdouble) icon->max_size / (gdouble) icon->dir_size;
else
icon->scale = (gdouble) scaled_desired_size / (icon->dir_size * dir_scale);
}
pixel_size = icon->desired_size * icon->desired_scale;
/* At this point, we need to actually get the icon; either from the
* builtin image or by loading the file
@ -3367,33 +3243,19 @@ icon_ensure_scale_and_texture__locked (GtkIconPaintable *icon,
{
if (icon->is_svg)
{
gint size;
if (icon->forced_size || icon->dir_type == ICON_THEME_DIR_UNTHEMED)
size = scaled_desired_size;
else
size = icon->dir_size * dir_scale * icon->scale;
if (gtk_icon_paintable_is_symbolic (icon))
source_pixbuf = gtk_make_symbolic_pixbuf_from_resource (icon->filename,
size, size,
pixel_size, pixel_size,
icon->desired_scale,
&icon->load_error);
else if (size == 0)
source_pixbuf = _gdk_pixbuf_new_from_resource_scaled (icon->filename,
"svg",
icon->desired_scale,
&icon->load_error);
else
source_pixbuf = _gdk_pixbuf_new_from_resource_at_scale (icon->filename,
"svg",
size, size, TRUE,
&icon->load_error);
pixel_size, pixel_size,
TRUE, &icon->load_error);
}
else
source_pixbuf = _gdk_pixbuf_new_from_resource (icon->filename,
"png",
&icon->load_error);
source_pixbuf = _gdk_pixbuf_new_from_resource (icon->filename, "png", &icon->load_error);
}
else
{
@ -3402,7 +3264,7 @@ icon_ensure_scale_and_texture__locked (GtkIconPaintable *icon,
loadable = icon_get_loadable (icon);
stream = g_loadable_icon_load (loadable,
scaled_desired_size,
pixel_size,
NULL, NULL,
&icon->load_error);
g_object_unref (loadable);
@ -3414,36 +3276,20 @@ icon_ensure_scale_and_texture__locked (GtkIconPaintable *icon,
*/
if (icon->is_svg)
{
gint size;
if (icon->forced_size || icon->dir_type == ICON_THEME_DIR_UNTHEMED)
size = scaled_desired_size;
else
size = icon->dir_size * dir_scale * icon->scale;
if (gtk_icon_paintable_is_symbolic (icon))
source_pixbuf = gtk_make_symbolic_pixbuf_from_path (icon->filename,
size, size,
pixel_size, pixel_size,
icon->desired_scale,
&icon->load_error);
else if (size == 0)
source_pixbuf = _gdk_pixbuf_new_from_stream_scaled (stream,
"svg",
icon->desired_scale,
NULL,
&icon->load_error);
else
source_pixbuf = _gdk_pixbuf_new_from_stream_at_scale (stream,
"svg",
size, size,
pixel_size, pixel_size,
TRUE, NULL,
&icon->load_error);
&icon->load_error);
}
else
source_pixbuf = _gdk_pixbuf_new_from_stream (stream,
"png",
NULL,
&icon->load_error);
source_pixbuf = _gdk_pixbuf_new_from_stream (stream, "png", NULL, &icon->load_error);
g_object_unref (stream);
}
}
@ -3473,42 +3319,12 @@ icon_ensure_scale_and_texture__locked (GtkIconPaintable *icon,
return FALSE;
}
/* Do scale calculations that depend on the image size
*/
image_width = gdk_pixbuf_get_width (source_pixbuf);
image_height = gdk_pixbuf_get_height (source_pixbuf);
image_size = MAX (image_width, image_height);
if (icon->is_svg)
icon->scale = image_size / 1000.;
else if (icon->scale < 0.0)
{
if (image_size > 0 && scaled_desired_size > 0)
icon->scale = (gdouble)scaled_desired_size / (gdouble)image_size;
else
icon->scale = 1.0;
}
if (icon->is_svg ||
icon->scale == 1.0)
{
icon->texture = gdk_texture_new_for_pixbuf (source_pixbuf);
g_object_unref (source_pixbuf);
}
else
{
GdkPixbuf *scaled = gdk_pixbuf_scale_simple (source_pixbuf,
MAX (1, 0.5 + image_width * icon->scale),
MAX (1, 0.5 + image_height * icon->scale),
GDK_INTERP_BILINEAR);
icon->texture = gdk_texture_new_for_pixbuf (scaled);
g_object_unref (scaled);
g_object_unref (source_pixbuf);
}
/* Actual scaling is done during rendering, so just keep the source pixbuf as a texture */
icon->texture = gdk_texture_new_for_pixbuf (source_pixbuf);
g_object_unref (source_pixbuf);
g_assert (icon->texture != NULL);
if (gdk_profiler_is_running ())
{
char *message = g_strdup_printf ("%s size %d@%d", icon->filename, icon->desired_size, icon->desired_scale);
@ -3538,7 +3354,7 @@ gtk_icon_paintable_download_texture (GtkIconPaintable *self,
g_mutex_lock (&self->texture_lock);
icon_ensure_scale_and_texture__locked (self, FALSE);
icon_ensure_texture__locked (self, FALSE);
if (self->texture)
texture = g_object_ref (self->texture);
@ -3632,18 +3448,15 @@ gtk_icon_paintable_snapshot_with_colors (GtkIconPaintable *icon,
const GdkRGBA *error_color)
{
GdkTexture *texture;
int texture_width, texture_height;
double render_width;
double render_height;
texture = gtk_icon_paintable_download_texture (icon, NULL);
if (texture)
{
gboolean symbolic = gtk_icon_paintable_is_symbolic (icon);
if (icon->desired_scale != 1)
{
gtk_snapshot_save (snapshot);
gtk_snapshot_scale (snapshot, 1.0 / icon->desired_scale, 1.0 / icon->desired_scale);
}
if (symbolic)
{
graphene_matrix_t matrix;
@ -3656,15 +3469,31 @@ gtk_icon_paintable_snapshot_with_colors (GtkIconPaintable *icon,
gtk_snapshot_push_color_matrix (snapshot, &matrix, &offset);
}
texture_width = gdk_texture_get_width (texture);
texture_height = gdk_texture_get_width (texture);
/* Keep aspect ratio and center */
if (texture_width >= texture_height)
{
render_width = width;
render_height = height * ((double)texture_height / texture_width);
}
else
{
render_width = width * ((double)texture_width / texture_height);
render_height = height;
}
gtk_snapshot_append_texture (snapshot, texture,
&GRAPHENE_RECT_INIT (0, 0, width * icon->desired_scale, height * icon->desired_scale));
&GRAPHENE_RECT_INIT ((width - render_width) / 2,
(height - render_height) / 2,
render_width,
render_width));
if (symbolic)
gtk_snapshot_pop (snapshot);
if (icon->desired_scale != 1)
gtk_snapshot_restore (snapshot);
g_object_unref (texture);
}
}
@ -3681,7 +3510,7 @@ icon_paintable_get_intrinsic_width (GdkPaintable *paintable)
{
GtkIconPaintable *icon = GTK_ICON_PAINTABLE (paintable);
return icon->rendered_size;
return icon->desired_size;
}
static int
@ -3689,7 +3518,7 @@ icon_paintable_get_intrinsic_height (GdkPaintable *paintable)
{
GtkIconPaintable *icon = GTK_ICON_PAINTABLE (paintable);
return icon->rendered_size;
return icon->desired_size;
}
static void
@ -3703,12 +3532,12 @@ icon_paintable_init (GdkPaintableInterface *iface)
static GtkIconPaintable *
gtk_icon_paintable_new_for_file (GFile *file,
gint size,
gint scale)
gint size,
gint scale)
{
GtkIconPaintable *icon;
icon = icon_paintable_new (ICON_THEME_DIR_UNTHEMED, size, 1);
icon = icon_paintable_new (size, scale);
icon->loadable = G_LOADABLE_ICON (g_file_icon_new (file));
icon->is_resource = g_file_has_uri_scheme (file, "resource");
@ -3727,12 +3556,6 @@ gtk_icon_paintable_new_for_file (GFile *file,
icon->is_svg = suffix_from_name (icon->filename) == ICON_CACHE_FLAG_SVG_SUFFIX;
icon->desired_size = size;
icon->desired_scale = scale;
icon->forced_size = FALSE;
icon->rendered_size = size;
return icon;
}
@ -3747,12 +3570,8 @@ gtk_icon_paintable_new_for_pixbuf (GtkIconTheme *icon_theme,
height = gdk_pixbuf_get_height (pixbuf);
max = MAX (width, height);
icon = icon_paintable_new (ICON_THEME_DIR_UNTHEMED, 0, 1);
icon = icon_paintable_new (max, 1);
icon->texture = gdk_texture_new_for_pixbuf (pixbuf);
icon->desired_size = max;
icon->desired_scale = 1.0;
icon->scale = 1.0;
icon->rendered_size = max;
return icon;
}
@ -3790,34 +3609,26 @@ gtk_icon_theme_lookup_by_gicon (GtkIconTheme *self,
if (GDK_IS_PIXBUF (gicon))
{
GdkPixbuf *pixbuf;
int width, height, max;
double pixbuf_scale;
pixbuf = GDK_PIXBUF (gicon);
if ((flags & GTK_ICON_LOOKUP_FORCE_SIZE) != 0)
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
max = MAX (width, height);
pixbuf_scale = (gdouble) size * scale / (gdouble) max;
if (pixbuf_scale != 1.0)
{
gint width, height, max;
gdouble pixbuf_scale;
GdkPixbuf *scaled;
scaled = gdk_pixbuf_scale_simple (pixbuf,
0.5 + width * pixbuf_scale,
0.5 + height * pixbuf_scale,
GDK_INTERP_BILINEAR);
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
max = MAX (width, height);
pixbuf_scale = (gdouble) size * scale / (gdouble) max;
if (pixbuf_scale != 1.0)
{
GdkPixbuf *scaled;
scaled = gdk_pixbuf_scale_simple (pixbuf,
0.5 + width * pixbuf_scale,
0.5 + height * pixbuf_scale,
GDK_INTERP_BILINEAR);
icon = gtk_icon_paintable_new_for_pixbuf (self, scaled);
g_object_unref (scaled);
}
else
{
icon = gtk_icon_paintable_new_for_pixbuf (self, pixbuf);
}
icon = gtk_icon_paintable_new_for_pixbuf (self, scaled);
g_object_unref (scaled);
}
else
{
@ -3831,18 +3642,14 @@ gtk_icon_theme_lookup_by_gicon (GtkIconTheme *self,
GFile *file = g_file_icon_get_file (G_FILE_ICON (gicon));
icon = gtk_icon_paintable_new_for_file (file, size, scale);
icon->forced_size = (flags & GTK_ICON_LOOKUP_FORCE_SIZE) != 0;
return icon;
}
else if (G_IS_LOADABLE_ICON (gicon))
{
icon = icon_paintable_new (ICON_THEME_DIR_UNTHEMED, size, 1);
icon = icon_paintable_new (size, scale);
icon->loadable = G_LOADABLE_ICON (g_object_ref (gicon));
icon->is_svg = FALSE;
icon->desired_size = size;
icon->desired_scale = scale;
icon->forced_size = (flags & GTK_ICON_LOOKUP_FORCE_SIZE) != 0;
return icon;
}

View File

@ -40,8 +40,6 @@ typedef struct _GtkIconTheme GtkIconTheme;
/**
* GtkIconLookupFlags:
* @GTK_ICON_LOOKUP_FORCE_SIZE: Always get the icon scaled to the
* requested size
* @GTK_ICON_LOOKUP_FORCE_REGULAR: Try to always load regular icons, even
* when symbolic icon names are given
* @GTK_ICON_LOOKUP_FORCE_SYMBOLIC: Try to always load symbolic icons, even
@ -51,9 +49,8 @@ typedef struct _GtkIconTheme GtkIconTheme;
*/
typedef enum
{
GTK_ICON_LOOKUP_FORCE_SIZE = 1 << 0,
GTK_ICON_LOOKUP_FORCE_REGULAR = 1 << 1,
GTK_ICON_LOOKUP_FORCE_SYMBOLIC = 1 << 2
GTK_ICON_LOOKUP_FORCE_REGULAR = 1 << 0,
GTK_ICON_LOOKUP_FORCE_SYMBOLIC = 1 << 1
} GtkIconLookupFlags;
/**

View File

@ -4116,7 +4116,7 @@ gtk_window_get_icon_for_size (GtkWindow *window,
info = gtk_icon_theme_lookup_icon (gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (window))),
name, NULL, size, priv->scale,
gtk_widget_get_direction (GTK_WIDGET (window)),
GTK_ICON_LOOKUP_FORCE_SIZE);
0);
if (info == NULL)
return NULL;

View File

@ -593,24 +593,20 @@ test_symbolic_single_size (void)
static void
test_svg_size (void)
{
/* To understand these results, keep in mind that we never allow upscaling,
* and don't respect min/max size for scaling (though we do take it into
* account for choosing).
*/
/* Check we properly load a svg icon from a sized directory */
assert_icon_lookup_size ("twosize-fixed", 48, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/32x32/twosize-fixed.svg", 32);
assert_icon_lookup_size ("twosize-fixed", 48, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/32x32/twosize-fixed.svg", 48);
assert_icon_lookup_size ("twosize-fixed", 32, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/32x32/twosize-fixed.svg", 32);
assert_icon_lookup_size ("twosize-fixed", 20, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/32x32/twosize-fixed.svg", 32);
assert_icon_lookup_size ("twosize-fixed", 20, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/32x32/twosize-fixed.svg", 20);
assert_icon_lookup_size ("twosize-fixed", 16, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/16x16/twosize-fixed.svg", 16);
/* Check that we still properly load it even if a different size is requested */
assert_icon_lookup_size ("twosize", 64, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/32x32s/twosize.svg", 48);
assert_icon_lookup_size ("twosize", 64, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/32x32s/twosize.svg", 64);
assert_icon_lookup_size ("twosize", 48, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/32x32s/twosize.svg", 48);
assert_icon_lookup_size ("twosize", 32, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/32x32s/twosize.svg", 32);
assert_icon_lookup_size ("twosize", 24, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/32x32s/twosize.svg", 24);
assert_icon_lookup_size ("twosize", 16, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/16x16s/twosize.svg", 16);
assert_icon_lookup_size ("twosize", 12, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/16x16s/twosize.svg", 12);
assert_icon_lookup_size ("twosize", 8, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/16x16s/twosize.svg", 12);
assert_icon_lookup_size ("twosize", 8, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/16x16s/twosize.svg", 8);
}
static void
@ -625,42 +621,21 @@ test_size (void)
assert_icon_lookup_size ("size-test", 18, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/16-22/size-test.png", 19);
assert_icon_lookup_size ("size-test", 19, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/16-22/size-test.png", 19);
/* the next 3 are because we never scale up */
assert_icon_lookup_size ("size-test", 20, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/25+/size-test.svg", 25);
assert_icon_lookup_size ("size-test", 21, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/25+/size-test.svg", 25);
assert_icon_lookup_size ("size-test", 22, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/25+/size-test.svg", 25);
assert_icon_lookup_size ("size-test", 20, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/25+/size-test.svg", 20);
assert_icon_lookup_size ("size-test", 21, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/25+/size-test.svg", 21);
assert_icon_lookup_size ("size-test", 22, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/25+/size-test.svg", 22);
assert_icon_lookup_size ("size-test", 23, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/25+/size-test.svg", 25);
assert_icon_lookup_size ("size-test", 23, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/25+/size-test.svg", 25);
assert_icon_lookup_size ("size-test", 23, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/25+/size-test.svg", 23);
assert_icon_lookup_size ("size-test", 23, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/25+/size-test.svg", 23);
assert_icon_lookup_size ("size-test", 25, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/25+/size-test.svg", 25);
assert_icon_lookup_size ("size-test", 28, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/25+/size-test.svg", 28);
/* the next 2 are because we never scale up */
assert_icon_lookup_size ("size-test", 31, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/35+/size-test.svg", 35);
assert_icon_lookup_size ("size-test", 34, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/35+/size-test.svg", 35);
assert_icon_lookup_size ("size-test", 31, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/35+/size-test.svg", 31);
assert_icon_lookup_size ("size-test", 34, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/35+/size-test.svg", 34);
assert_icon_lookup_size ("size-test", 37, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/35+/size-test.svg", 37);
assert_icon_lookup_size ("size-test", 40, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/35+/size-test.svg", 40);
assert_icon_lookup_size ("size-test", 45, GTK_TEXT_DIR_NONE, 0, FALSE, "/icons/35+/size-test.svg", 45);
assert_icon_lookup_size ("size-test", 12, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/15/size-test.png", 12);
assert_icon_lookup_size ("size-test", 13, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/15/size-test.png", 13);
assert_icon_lookup_size ("size-test", 14, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/15/size-test.png", 14);
assert_icon_lookup_size ("size-test", 15, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/15/size-test.png", 15);
assert_icon_lookup_size ("size-test", 16, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/16-22/size-test.png", 16);
assert_icon_lookup_size ("size-test", 17, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/16-22/size-test.png", 17);
assert_icon_lookup_size ("size-test", 18, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/16-22/size-test.png", 18);
assert_icon_lookup_size ("size-test", 19, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/16-22/size-test.png", 19);
//assert_icon_lookup_size ("size-test", 20, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/16-22/size-test.png", 20);
//assert_icon_lookup_size ("size-test", 21, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/16-22/size-test.png", 21);
//assert_icon_lookup_size ("size-test", 22, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/16-22/size-test.png", 22);
assert_icon_lookup_size ("size-test", 23, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/25+/size-test.svg", 23);
assert_icon_lookup_size ("size-test", 24, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/25+/size-test.svg", 24);
assert_icon_lookup_size ("size-test", 25, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/25+/size-test.svg", 25);
assert_icon_lookup_size ("size-test", 28, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/25+/size-test.svg", 28);
//assert_icon_lookup_size ("size-test", 31, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/25+/size-test.svg", 31);
//assert_icon_lookup_size ("size-test", 34, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/25+/size-test.svg", 34);
assert_icon_lookup_size ("size-test", 37, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/35+/size-test.svg", 37);
assert_icon_lookup_size ("size-test", 40, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/35+/size-test.svg", 40);
assert_icon_lookup_size ("size-test", 45, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_FORCE_SIZE, FALSE, "/icons/35+/size-test.svg", 45);
}
static void