summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2017-11-07 18:55:01 -0500
committerMatthias Clasen <mclasen@redhat.com>2017-11-07 18:56:32 -0500
commit284fd36e5d3f1297a6e443971802f9191b11f42a (patch)
tree910ce994b2899fcdb1aeaf3e95f26d0efd6bd946
parent73a3d4b785205319013a79d8d509296bb2b1fd24 (diff)
downloadgtk+-284fd36e5d3f1297a6e443971802f9191b11f42a.tar.gz
Fix symbolic.svg rendering
With the shader approach to symbolic recoloring, we must not recolor the svgs anymore as we're loading them. Instead, load them the same way that gtk-encode-symbolic-svg does. This fixes the rendering of large symbolic icons e.g. the 'no search results found' page in the file chooser.
-rw-r--r--gtk/encodesymbolic.c197
-rw-r--r--gtk/gdkpixbufutils.c212
-rw-r--r--gtk/gdkpixbufutilsprivate.h13
-rw-r--r--gtk/gtkicontheme.c13
-rw-r--r--gtk/meson.build2
5 files changed, 252 insertions, 185 deletions
diff --git a/gtk/encodesymbolic.c b/gtk/encodesymbolic.c
index 3b24ca7dba..d1cc6069ec 100644
--- a/gtk/encodesymbolic.c
+++ b/gtk/encodesymbolic.c
@@ -18,7 +18,6 @@
#include "config.h"
#include <glib.h>
-#include <gdk-pixbuf/gdk-pixdata.h>
#include <gdk/gdk.h>
#include <glib/gi18n.h>
@@ -32,6 +31,8 @@
#include <stdlib.h>
#include <locale.h>
+#include "gtkpixbufutilsprivate.h"
+
static gchar *output_dir = NULL;
static GOptionEntry args[] = {
@@ -39,184 +40,6 @@ static GOptionEntry args[] = {
{ NULL }
};
-static GdkPixbuf *
-load_symbolic_svg (char *file_data, gsize file_len,
- int width,
- int height,
- const GdkRGBA *fg,
- const GdkRGBA *success_color,
- const GdkRGBA *warning_color,
- const GdkRGBA *error_color,
- GError **error)
-{
- GInputStream *stream;
- GdkPixbuf *pixbuf;
- gchar *css_fg;
- gchar *css_success;
- gchar *css_warning;
- gchar *css_error;
- gchar *data;
- gchar *svg_width, *svg_height;
- gchar *escaped_file_data;
-
- css_fg = gdk_rgba_to_string (fg);
-
- css_success = css_warning = css_error = NULL;
-
- css_warning = gdk_rgba_to_string (warning_color);
- css_error = gdk_rgba_to_string (error_color);
- css_success = gdk_rgba_to_string (success_color);
-
- /* Fetch size from the original icon */
- stream = g_memory_input_stream_new_from_data (file_data, file_len, NULL);
- pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, error);
- g_object_unref (stream);
-
- if (!pixbuf)
- return NULL;
-
- svg_width = g_strdup_printf ("%d", gdk_pixbuf_get_width (pixbuf));
- svg_height = g_strdup_printf ("%d",gdk_pixbuf_get_height (pixbuf));
- g_object_unref (pixbuf);
-
- escaped_file_data = g_markup_escape_text (file_data, file_len);
-
- data = g_strconcat ("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
- "<svg version=\"1.1\"\n"
- " xmlns=\"http://www.w3.org/2000/svg\"\n"
- " xmlns:xi=\"http://www.w3.org/2001/XInclude\"\n"
- " width=\"", svg_width, "\"\n"
- " height=\"", svg_height, "\">\n"
- " <style type=\"text/css\">\n"
- " rect,circle,path {\n"
- " fill: ", css_fg," !important;\n"
- " }\n"
- " .warning {\n"
- " fill: ", css_warning, " !important;\n"
- " }\n"
- " .error {\n"
- " fill: ", css_error ," !important;\n"
- " }\n"
- " .success {\n"
- " fill: ", css_success, " !important;\n"
- " }\n"
- " </style>\n"
- " <xi:include href=\"data:text/xml,", escaped_file_data, "\"/>\n"
- "</svg>",
- NULL);
- g_free (escaped_file_data);
- g_free (css_fg);
- g_free (css_warning);
- g_free (css_error);
- g_free (css_success);
- g_free (svg_width);
- g_free (svg_height);
-
- stream = g_memory_input_stream_new_from_data (data, -1, g_free);
- pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream,
- width,
- height,
- TRUE,
- NULL,
- error);
- g_object_unref (stream);
-
- return pixbuf;
-}
-
-static void
-extract_plane (GdkPixbuf *src,
- GdkPixbuf *dst,
- int from_plane,
- int to_plane)
-{
- guchar *src_data, *dst_data;
- int width, height, src_stride, dst_stride;
- guchar *src_row, *dst_row;
- int x, y;
-
- width = gdk_pixbuf_get_width (src);
- height = gdk_pixbuf_get_height (src);
-
- g_assert (width <= gdk_pixbuf_get_width (dst));
- g_assert (height <= gdk_pixbuf_get_height (dst));
-
- src_stride = gdk_pixbuf_get_rowstride (src);
- src_data = gdk_pixbuf_get_pixels (src);
-
- dst_data = gdk_pixbuf_get_pixels (dst);
- dst_stride = gdk_pixbuf_get_rowstride (dst);
-
- 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++)
- {
- dst_row[to_plane] = src_row[from_plane];
- src_row += 4;
- dst_row += 4;
- }
- }
-}
-
-static GdkPixbuf *
-make_symbolic_pixbuf (char *file,
- int width,
- int height,
- GError **error)
-
-{
- GdkRGBA r = { 1,0,0,1}, g = {0,1,0,1};
- GdkPixbuf *loaded;
- GdkPixbuf *pixbuf;
- int plane;
- gchar *file_data;
- gsize file_len;
-
- if (!g_file_get_contents (file, &file_data, &file_len, error))
- return NULL;
-
- pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
-
- gdk_pixbuf_fill (pixbuf, 0);
-
- for (plane = 0; plane < 3; plane++)
- {
- /* Here we render the svg with all colors solid, this should
- * always make the alpha channel the same and it should match
- * the final alpha channel for all possible renderings. We
- * Just use it as-is for final alpha.
- *
- * For the 3 non-fg colors, we render once each with that
- * color as red, and every other color as green. The resulting
- * red will describe the amount of that color is in the
- * opaque part of the color. We store these as the rgb
- * channels, with the color of the fg being implicitly
- * the "rest", as all color fractions should add up to 1.
- */
- loaded = load_symbolic_svg (file_data, file_len, width, height,
- &g,
- plane == 0 ? &r : &g,
- plane == 1 ? &r : &g,
- plane == 2 ? &r : &g,
- error);
- if (loaded == NULL)
- return NULL;
-
- if (plane == 0)
- extract_plane (loaded, pixbuf, 3, 3);
-
- extract_plane (loaded, pixbuf, 0, plane);
-
- g_object_unref (loaded);
- }
-
- g_free (file_data);
-
- return pixbuf;
-}
-
int
main (int argc, char **argv)
{
@@ -228,6 +51,8 @@ main (int argc, char **argv)
gchar **sizev;
GFileOutputStream *out;
GFile *dest;
+ char *data;
+ gsize len;
setlocale (LC_ALL, "");
@@ -254,12 +79,12 @@ main (int argc, char **argv)
width = 0;
height = 0;
sizev = g_strsplit (argv[2], "x", 0);
- if (g_strv_length (sizev) == 2)
+ if (g_strv_length (sizev) == 2)
{
width = atoi(sizev[0]);
height = atoi(sizev[1]);
}
- g_strfreev (sizev);
+ g_strfreev (sizev);
if (width == 0 || height == 0)
{
@@ -273,13 +98,21 @@ main (int argc, char **argv)
#endif
error = NULL;
- symbolic = make_symbolic_pixbuf (path, width, height, &error);
+ if (!g_file_get_contents (path, &data, &len, &error))
+ {
+ g_printerr (_("Can’t load file: %s\n"), error->message);
+ return 1;
+ }
+
+ symbolic = gtk_make_symbolic_pixbuf_from_data (data, len, width, height, &error);
if (symbolic == NULL)
{
g_printerr (_("Can’t load file: %s\n"), error->message);
return 1;
}
+ g_free (data);
+
basename = g_path_get_basename (path);
dot = strrchr (basename, '.');
diff --git a/gtk/gdkpixbufutils.c b/gtk/gdkpixbufutils.c
index 3da0323623..ac9863a64f 100644
--- a/gtk/gdkpixbufutils.c
+++ b/gtk/gdkpixbufutils.c
@@ -16,6 +16,7 @@
#include "config.h"
+#include <gdk/gdk.h>
#include "gdkpixbufutilsprivate.h"
static GdkPixbuf *
@@ -130,3 +131,214 @@ _gdk_pixbuf_new_from_resource_scaled (const gchar *resource_path,
return pixbuf;
}
+static GdkPixbuf *
+load_symbolic_svg (const char *file_data,
+ gsize file_len,
+ int width,
+ int height,
+ const GdkRGBA *fg,
+ const GdkRGBA *success_color,
+ const GdkRGBA *warning_color,
+ const GdkRGBA *error_color,
+ GError **error)
+{
+ GInputStream *stream;
+ GdkPixbuf *pixbuf;
+ gchar *css_fg;
+ gchar *css_success;
+ gchar *css_warning;
+ gchar *css_error;
+ gchar *data;
+ gchar *svg_width, *svg_height;
+ gchar *escaped_file_data;
+
+ css_fg = gdk_rgba_to_string (fg);
+
+ css_success = css_warning = css_error = NULL;
+
+ css_warning = gdk_rgba_to_string (warning_color);
+ css_error = gdk_rgba_to_string (error_color);
+ css_success = gdk_rgba_to_string (success_color);
+
+ /* Fetch size from the original icon */
+ stream = g_memory_input_stream_new_from_data (file_data, file_len, NULL);
+ pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, error);
+ g_object_unref (stream);
+
+ if (!pixbuf)
+ return NULL;
+
+ svg_width = g_strdup_printf ("%d", gdk_pixbuf_get_width (pixbuf));
+ svg_height = g_strdup_printf ("%d",gdk_pixbuf_get_height (pixbuf));
+ g_object_unref (pixbuf);
+
+ escaped_file_data = g_markup_escape_text (file_data, file_len);
+
+ data = g_strconcat ("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+ "<svg version=\"1.1\"\n"
+ " xmlns=\"http://www.w3.org/2000/svg\"\n"
+ " xmlns:xi=\"http://www.w3.org/2001/XInclude\"\n"
+ " width=\"", svg_width, "\"\n"
+ " height=\"", svg_height, "\">\n"
+ " <style type=\"text/css\">\n"
+ " rect,circle,path {\n"
+ " fill: ", css_fg," !important;\n"
+ " }\n"
+ " .warning {\n"
+ " fill: ", css_warning, " !important;\n"
+ " }\n"
+ " .error {\n"
+ " fill: ", css_error ," !important;\n"
+ " }\n"
+ " .success {\n"
+ " fill: ", css_success, " !important;\n"
+ " }\n"
+ " </style>\n"
+ " <xi:include href=\"data:text/xml,", escaped_file_data, "\"/>\n"
+ "</svg>",
+ NULL);
+ g_free (escaped_file_data);
+ g_free (css_fg);
+ g_free (css_warning);
+ g_free (css_error);
+ g_free (css_success);
+ g_free (svg_width);
+ g_free (svg_height);
+
+ stream = g_memory_input_stream_new_from_data (data, -1, g_free);
+ pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream, width, height, TRUE, NULL, error);
+ g_object_unref (stream);
+
+ return pixbuf;
+}
+
+static void
+extract_plane (GdkPixbuf *src,
+ GdkPixbuf *dst,
+ int from_plane,
+ int to_plane)
+{
+ guchar *src_data, *dst_data;
+ int width, height, src_stride, dst_stride;
+ guchar *src_row, *dst_row;
+ int x, y;
+
+ width = gdk_pixbuf_get_width (src);
+ height = gdk_pixbuf_get_height (src);
+
+ g_assert (width <= gdk_pixbuf_get_width (dst));
+ g_assert (height <= gdk_pixbuf_get_height (dst));
+
+ src_stride = gdk_pixbuf_get_rowstride (src);
+ src_data = gdk_pixbuf_get_pixels (src);
+
+ dst_data = gdk_pixbuf_get_pixels (dst);
+ dst_stride = gdk_pixbuf_get_rowstride (dst);
+
+ 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++)
+ {
+ dst_row[to_plane] = src_row[from_plane];
+ src_row += 4;
+ dst_row += 4;
+ }
+ }
+}
+
+GdkPixbuf *
+gtk_make_symbolic_pixbuf_from_data (const char *file_data,
+ gsize file_len,
+ int width,
+ int height,
+ GError **error)
+
+{
+ GdkRGBA r = { 1,0,0,1}, g = {0,1,0,1};
+ GdkPixbuf *loaded;
+ GdkPixbuf *pixbuf;
+ int plane;
+
+ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
+
+ gdk_pixbuf_fill (pixbuf, 0);
+
+ for (plane = 0; plane < 3; plane++)
+ {
+ /* Here we render the svg with all colors solid, this should
+ * always make the alpha channel the same and it should match
+ * the final alpha channel for all possible renderings. We
+ * Just use it as-is for final alpha.
+ *
+ * For the 3 non-fg colors, we render once each with that
+ * color as red, and every other color as green. The resulting
+ * red will describe the amount of that color is in the
+ * opaque part of the color. We store these as the rgb
+ * channels, with the color of the fg being implicitly
+ * the "rest", as all color fractions should add up to 1.
+ */
+ loaded = load_symbolic_svg (file_data, file_len, width, height,
+ &g,
+ plane == 0 ? &r : &g,
+ plane == 1 ? &r : &g,
+ plane == 2 ? &r : &g,
+ error);
+ if (loaded == NULL)
+ return NULL;
+
+ if (plane == 0)
+ extract_plane (loaded, pixbuf, 3, 3);
+
+ extract_plane (loaded, pixbuf, 0, plane);
+
+ g_object_unref (loaded);
+ }
+
+ return pixbuf;
+}
+
+GdkPixbuf *
+gtk_make_symbolic_pixbuf_from_resource (const char *path,
+ int width,
+ int height,
+ GError **error)
+{
+ GBytes *bytes;
+ const char *data;
+ gsize size;
+ GdkPixbuf *pixbuf;
+
+ bytes = g_resources_lookup_data (path, G_RESOURCE_LOOKUP_FLAGS_NONE, error);
+ if (bytes == NULL)
+ return NULL;
+
+ data = g_bytes_get_data (bytes, &size);
+
+ pixbuf = gtk_make_symbolic_pixbuf_from_data (data, size, width, height, error);
+
+ g_bytes_unref (bytes);
+
+ return pixbuf;
+}
+
+GdkPixbuf *
+gtk_make_symbolic_pixbuf_from_file (GFile *file,
+ int width,
+ int height,
+ GError **error)
+{
+ char *data;
+ gsize size;
+ GdkPixbuf *pixbuf;
+
+ if (!g_file_load_contents (file, NULL, &data, &size, NULL, error))
+ return NULL;
+
+ pixbuf = gtk_make_symbolic_pixbuf_from_data (data, size, width, height, error);
+
+ g_free (data);
+
+ return pixbuf;
+}
diff --git a/gtk/gdkpixbufutilsprivate.h b/gtk/gdkpixbufutilsprivate.h
index f01f1774b6..1ea23dc2a2 100644
--- a/gtk/gdkpixbufutilsprivate.h
+++ b/gtk/gdkpixbufutilsprivate.h
@@ -30,6 +30,19 @@ GdkPixbuf *_gdk_pixbuf_new_from_resource_scaled (const gchar *resource_path,
gdouble scale,
GError **error);
+GdkPixbuf *gtk_make_symbolic_pixbuf_from_data (const char *data,
+ gsize len,
+ int width,
+ int height,
+ GError **error);
+GdkPixbuf *gtk_make_symbolic_pixbuf_from_file (GFile *file,
+ int width,
+ int height,
+ GError **error);
+GdkPixbuf *gtk_make_symbolic_pixbuf_from_resource (const char *path,
+ int width,
+ int height,
+ GError **error);
G_END_DECLS
#endif /* __GDK_PIXBUF_UTILS_PRIVATE_H__ */
diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c
index f738579644..94e032388a 100644
--- a/gtk/gtkicontheme.c
+++ b/gtk/gtkicontheme.c
@@ -3793,7 +3793,11 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info)
else
size = icon_info->dir_size * dir_scale * icon_info->scale;
- if (size == 0)
+ if (gtk_icon_info_is_symbolic (icon_info))
+ source_pixbuf = gtk_make_symbolic_pixbuf_from_resource (icon_info->filename,
+ size, size,
+ &icon_info->load_error);
+ else if (size == 0)
source_pixbuf = _gdk_pixbuf_new_from_resource_scaled (icon_info->filename,
icon_info->desired_scale,
&icon_info->load_error);
@@ -3828,7 +3832,12 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info)
size = scaled_desired_size;
else
size = icon_info->dir_size * dir_scale * icon_info->scale;
- if (size == 0)
+
+ if (gtk_icon_info_is_symbolic (icon_info) && icon_info->icon_file)
+ source_pixbuf = gtk_make_symbolic_pixbuf_from_file (icon_info->icon_file,
+ size, size,
+ &icon_info->load_error);
+ else if (size == 0)
source_pixbuf = _gdk_pixbuf_new_from_stream_scaled (stream,
icon_info->desired_scale,
NULL,
diff --git a/gtk/meson.build b/gtk/meson.build
index 166e81e1a1..8dedfdd4c0 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -1021,7 +1021,7 @@ gtk_tools = [
['gtk4-query-settings', ['gtk-query-settings.c']],
['gtk4-builder-tool', ['gtk-builder-tool.c']],
['gtk4-update-icon-cache', ['updateiconcache.c']],
- ['gtk4-encode-symbolic-svg', ['encodesymbolic.c']],
+ ['gtk4-encode-symbolic-svg', ['encodesymbolic.c', 'gdkpixbufutils.c']],
['gtk4-query-immodules', ['queryimmodules.c', 'gtkutils.c']],
]