icon-theme: Support recolorable .symbolic.png files

If an icon theme has a file called "foo-symbolic.symbolic.png" which
was converted from svg using gtk-encode-symbolic-svg we will read
it in an recolor, allowing symbolic icons without using librsvg.

https://bugzilla.gnome.org/show_bug.cgi?id=730450
This commit is contained in:
Alexander Larsson 2014-07-30 18:05:48 +02:00 committed by Matthias Clasen
parent 50ba3c72bb
commit 1d68801ade

View File

@ -151,7 +151,8 @@ typedef enum
ICON_SUFFIX_XPM = 1 << 0,
ICON_SUFFIX_SVG = 1 << 1,
ICON_SUFFIX_PNG = 1 << 2,
HAS_ICON_FILE = 1 << 3
HAS_ICON_FILE = 1 << 3,
ICON_SUFFIX_SYMBOLIC_PNG = 1 << 4
} IconSuffix;
#define INFO_CACHE_LRU_SIZE 32
@ -1251,6 +1252,9 @@ strip_suffix (const gchar *filename)
{
const gchar *dot;
if (g_str_has_suffix (filename, ".symbolic.png"))
return g_strndup (filename, strlen(filename)-13);
dot = strrchr (filename, '.');
if (dot == NULL)
@ -1633,7 +1637,8 @@ icon_uri_is_symbolic (const gchar *icon_name)
{
return g_str_has_suffix (icon_name, "-symbolic.svg")
|| g_str_has_suffix (icon_name, "-symbolic-ltr.svg")
|| g_str_has_suffix (icon_name, "-symbolic-rtl.svg");
|| g_str_has_suffix (icon_name, "-symbolic-rtl.svg")
|| g_str_has_suffix (icon_name, ".symbolic.png");
}
static GtkIconInfo *
@ -1765,7 +1770,7 @@ real_choose_icon (GtkIconTheme *icon_theme,
if (allow_svg &&
unthemed_icon->svg_filename &&
(!unthemed_icon->no_svg_filename ||
suffix_from_name (unthemed_icon->no_svg_filename) != ICON_SUFFIX_PNG))
suffix_from_name (unthemed_icon->no_svg_filename) < ICON_SUFFIX_PNG))
icon_info->filename = g_strdup (unthemed_icon->svg_filename);
else if (unthemed_icon->no_svg_filename)
icon_info->filename = g_strdup (unthemed_icon->no_svg_filename);
@ -2824,6 +2829,8 @@ string_from_suffix (IconSuffix suffix)
return ".svg";
case ICON_SUFFIX_PNG:
return ".png";
case ICON_SUFFIX_SYMBOLIC_PNG:
return ".symbolic.png";
default:
g_assert_not_reached();
}
@ -2835,7 +2842,9 @@ suffix_from_name (const gchar *name)
{
IconSuffix retval;
if (g_str_has_suffix (name, ".png"))
if (g_str_has_suffix (name, ".symbolic.png"))
retval = ICON_SUFFIX_SYMBOLIC_PNG;
else if (g_str_has_suffix (name, ".png"))
retval = ICON_SUFFIX_PNG;
else if (g_str_has_suffix (name, ".svg"))
retval = ICON_SUFFIX_SVG;
@ -2851,7 +2860,9 @@ static IconSuffix
best_suffix (IconSuffix suffix,
gboolean allow_svg)
{
if ((suffix & ICON_SUFFIX_PNG) != 0)
if ((suffix & ICON_SUFFIX_SYMBOLIC_PNG) != 0)
return ICON_SUFFIX_SYMBOLIC_PNG;
else if ((suffix & ICON_SUFFIX_PNG) != 0)
return ICON_SUFFIX_PNG;
else if (allow_svg && ((suffix & ICON_SUFFIX_SVG) != 0))
return ICON_SUFFIX_SVG;
@ -2866,7 +2877,7 @@ theme_dir_get_icon_suffix (IconThemeDir *dir,
const gchar *icon_name,
gboolean *has_icon_file)
{
IconSuffix suffix;
IconSuffix suffix, symbolic_suffix;
if (dir->cache)
{
@ -2874,6 +2885,19 @@ theme_dir_get_icon_suffix (IconThemeDir *dir,
icon_name,
dir->subdir_index);
if (icon_name_is_symbolic (icon_name))
{
/* Look for foo-symbolic.symbolic.png, as the cache only stores the ".png" suffix */
char *icon_name_with_prefix = g_strconcat (icon_name, ".symbolic", NULL);
symbolic_suffix = (IconSuffix)_gtk_icon_cache_get_icon_flags (dir->cache,
icon_name_with_prefix,
dir->subdir_index);
g_free (icon_name_with_prefix);
if (symbolic_suffix & ICON_SUFFIX_PNG)
suffix = ICON_SUFFIX_SYMBOLIC_PNG;
}
if (has_icon_file)
*has_icon_file = suffix & HAS_ICON_FILE;
@ -4211,15 +4235,142 @@ symbolic_cache_get_proxy (SymbolicPixbufCache *symbolic_cache,
return symbolic_cache->proxy_pixbuf;
}
static void
rgba_to_pixel(const GdkRGBA *rgba,
guint8 pixel[4])
{
pixel[0] = rgba->red * 255;
pixel[1] = rgba->green * 255;
pixel[2] = rgba->blue * 255;
pixel[3] = rgba->alpha * 255;
}
static GdkPixbuf *
gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info,
const GdkRGBA *fg,
const GdkRGBA *success_color,
const GdkRGBA *warning_color,
const GdkRGBA *error_color,
gboolean use_cache,
GError **error)
color_symbolic_pixbuf (GdkPixbuf *symbolic,
const GdkRGBA *fg_color,
const GdkRGBA *success_color,
const GdkRGBA *warning_color,
const GdkRGBA *error_color)
{
int width, height, x, y, src_stride, dst_stride;
guchar *src_data, *dst_data;
guchar *src_row, *dst_row;
GdkPixbuf *colored;
guint8 fg_pixel[4], success_pixel[4], warning_pixel[4], error_pixel[4];
rgba_to_pixel (fg_color, fg_pixel);
rgba_to_pixel (success_color, success_pixel);
rgba_to_pixel (warning_color, warning_pixel);
rgba_to_pixel (error_color, error_pixel);
width = gdk_pixbuf_get_width (symbolic);
height = gdk_pixbuf_get_height (symbolic);
colored = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
src_stride = gdk_pixbuf_get_rowstride (symbolic);
src_data = gdk_pixbuf_get_pixels (symbolic);
dst_data = gdk_pixbuf_get_pixels (colored);
dst_stride = gdk_pixbuf_get_rowstride (colored);
for (y = 0; y < height; y++)
{
src_row = src_data + src_stride * y;
dst_row = dst_data + dst_stride * y;
for (x = 0; x < width; x++)
{
guint r, g, b, a;
int c1, c2, c3, c4;
a = src_row[3];
dst_row[3] = a;
if (a == 0)
{
dst_row[0] = 0;
dst_row[1] = 0;
dst_row[2] = 0;
}
else
{
c2 = src_row[0];
c3 = src_row[1];
c4 = src_row[2];
if (c2 == 0 && c3 == 0 && c4 == 0)
{
dst_row[0] = fg_pixel[0];
dst_row[1] = fg_pixel[1];
dst_row[2] = fg_pixel[2];
}
else
{
c1 = 255 - c2 - c3 - c4;
r = fg_pixel[0] * c1 + success_pixel[0] * c2 + warning_pixel[0] * c3 + error_pixel[0] * c4;
g = fg_pixel[1] * c1 + success_pixel[1] * c2 + warning_pixel[1] * c3 + error_pixel[1] * c4;
b = fg_pixel[2] * c1 + success_pixel[2] * c2 + warning_pixel[2] * c3 + error_pixel[2] * c4;
dst_row[0] = r / 255;
dst_row[1] = g / 255;
dst_row[2] = b / 255;
}
}
src_row += 4;
dst_row += 4;
}
}
return colored;
}
static GdkPixbuf *
gtk_icon_info_load_symbolic_png (GtkIconInfo *icon_info,
const GdkRGBA *fg,
const GdkRGBA *success_color,
const GdkRGBA *warning_color,
const GdkRGBA *error_color,
GError **error)
{
GdkRGBA fg_default = { 0.7450980392156863, 0.7450980392156863, 0.7450980392156863, 1.0};
GdkRGBA success_default = { 0.3046921492332342,0.6015716792553597, 0.023437857633325704, 1.0};
GdkRGBA warning_default = {0.9570458533607996, 0.47266346227206835, 0.2421911955443656, 1.0 };
GdkRGBA error_default = { 0.796887159533074, 0 ,0, 1.0 };
if (!icon_info_ensure_scale_and_pixbuf (icon_info))
{
if (icon_info->load_error)
{
if (error)
*error = g_error_copy (icon_info->load_error);
}
else
{
g_set_error_literal (error,
GTK_ICON_THEME_ERROR,
GTK_ICON_THEME_NOT_FOUND,
_("Failed to load icon"));
}
return NULL;
}
return color_symbolic_pixbuf (icon_info->pixbuf,
fg ? fg : &fg_default,
success_color ? success_color : &success_default,
warning_color ? warning_color : &warning_default,
error_color ? error_color : &error_default);
}
static GdkPixbuf *
gtk_icon_info_load_symbolic_svg (GtkIconInfo *icon_info,
const GdkRGBA *fg,
const GdkRGBA *success_color,
const GdkRGBA *warning_color,
const GdkRGBA *error_color,
GError **error)
{
GInputStream *stream;
GdkPixbuf *pixbuf;
@ -4231,20 +4382,6 @@ gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info,
gchar *size;
gchar *file_data, *escaped_file_data;
gsize file_len;
SymbolicPixbufCache *symbolic_cache;
if (use_cache)
{
symbolic_cache = symbolic_pixbuf_cache_matches (icon_info->symbolic_pixbuf_cache,
fg, success_color, warning_color, error_color);
if (symbolic_cache)
return symbolic_cache_get_proxy (symbolic_cache, icon_info);
}
/* css_fg can't possibly have failed, otherwise
* that would mean we have a broken style
*/
g_return_val_if_fail (fg != NULL, NULL);
css_fg = gdk_rgba_to_string (fg);
@ -4338,6 +4475,45 @@ gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info,
error);
g_object_unref (stream);
return pixbuf;
}
static GdkPixbuf *
gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info,
const GdkRGBA *fg,
const GdkRGBA *success_color,
const GdkRGBA *warning_color,
const GdkRGBA *error_color,
gboolean use_cache,
GError **error)
{
GdkPixbuf *pixbuf;
SymbolicPixbufCache *symbolic_cache;
char *icon_uri;
if (use_cache)
{
symbolic_cache = symbolic_pixbuf_cache_matches (icon_info->symbolic_pixbuf_cache,
fg, success_color, warning_color, error_color);
if (symbolic_cache)
return symbolic_cache_get_proxy (symbolic_cache, icon_info);
}
/* css_fg can't possibly have failed, otherwise
* that would mean we have a broken style
*/
g_return_val_if_fail (fg != NULL, NULL);
icon_uri = g_file_get_uri (icon_info->icon_file);
if (g_str_has_suffix (icon_uri, ".symbolic.png"))
pixbuf = gtk_icon_info_load_symbolic_png (icon_info, fg, success_color, warning_color, error_color, error);
else
pixbuf = gtk_icon_info_load_symbolic_svg (icon_info, fg, success_color, warning_color, error_color, error);
g_free (icon_uri);
if (pixbuf != NULL)
{
GdkPixbuf *icon;