mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-09-18 21:10:00 +00:00
Add 'only foreground' to texture utility api
Add an 'only_fg' argument to all our internal texture utility api, so GtkIconTheme can find out if a symbolic png or svg uses colors beyond the foreground or not. This information is used in gtk_symbolic_paintable_snapshot_symbolic to optimize rendering of such symbolic icons.
This commit is contained in:
parent
08d1353cde
commit
4862c3f779
@ -21,9 +21,16 @@
|
||||
#include "gtkscalerprivate.h"
|
||||
|
||||
#include "gdk/gdktextureprivate.h"
|
||||
#include "gdk/loaders/gdkpngprivate.h"
|
||||
|
||||
/* {{{ Pixbuf helpers */
|
||||
|
||||
static inline gboolean
|
||||
pixbuf_is_only_fg (GdkPixbuf *pixbuf)
|
||||
{
|
||||
return gdk_pixbuf_get_option (pixbuf, "tEXt::only-foreground") != NULL;
|
||||
}
|
||||
|
||||
static GdkPixbuf *
|
||||
load_from_stream (GdkPixbufLoader *loader,
|
||||
GInputStream *stream,
|
||||
@ -246,7 +253,7 @@ load_symbolic_svg (const char *escaped_file_data,
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
extract_plane (GdkPixbuf *src,
|
||||
GdkPixbuf *dst,
|
||||
int from_plane,
|
||||
@ -257,6 +264,7 @@ extract_plane (GdkPixbuf *src,
|
||||
gsize src_stride, dst_stride;
|
||||
guchar *src_row, *dst_row;
|
||||
int x, y;
|
||||
gboolean all_clear = TRUE;
|
||||
|
||||
width = gdk_pixbuf_get_width (src);
|
||||
height = gdk_pixbuf_get_height (src);
|
||||
@ -276,11 +284,16 @@ extract_plane (GdkPixbuf *src,
|
||||
dst_row = dst_data + dst_stride * y;
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
if (src_row[from_plane] != 0)
|
||||
all_clear = FALSE;
|
||||
|
||||
dst_row[to_plane] = src_row[from_plane];
|
||||
src_row += 4;
|
||||
dst_row += 4;
|
||||
}
|
||||
}
|
||||
|
||||
return all_clear;
|
||||
}
|
||||
|
||||
GdkPixbuf *
|
||||
@ -303,6 +316,7 @@ gtk_make_symbolic_pixbuf_from_data (const char *file_data,
|
||||
int icon_width, icon_height;
|
||||
char *escaped_file_data;
|
||||
gsize len;
|
||||
gboolean only_fg;
|
||||
|
||||
/* Fetch size from the original icon */
|
||||
GInputStream *stream = g_memory_input_stream_new_from_data (file_data, file_len, NULL);
|
||||
@ -328,6 +342,7 @@ gtk_make_symbolic_pixbuf_from_data (const char *file_data,
|
||||
if (height == 0)
|
||||
height = icon_height * scale;
|
||||
|
||||
only_fg = TRUE;
|
||||
for (plane = 0; plane < 3; plane++)
|
||||
{
|
||||
/* Here we render the svg with all colors solid, this should
|
||||
@ -374,11 +389,14 @@ gtk_make_symbolic_pixbuf_from_data (const char *file_data,
|
||||
if (plane == 0)
|
||||
extract_plane (loaded, pixbuf, 3, 3);
|
||||
|
||||
extract_plane (loaded, pixbuf, 0, plane);
|
||||
only_fg &= extract_plane (loaded, pixbuf, 0, plane);
|
||||
|
||||
g_object_unref (loaded);
|
||||
}
|
||||
|
||||
if (only_fg)
|
||||
gdk_pixbuf_set_option (pixbuf, "tEXt::only-foreground", "true");
|
||||
|
||||
g_free (escaped_file_data);
|
||||
|
||||
out:
|
||||
@ -458,11 +476,65 @@ make_symbolic_pixbuf_from_file (GFile *file,
|
||||
/* }}} */
|
||||
/* {{{ Texture API */
|
||||
|
||||
static GdkTexture *
|
||||
texture_new_from_bytes (GBytes *bytes,
|
||||
gboolean *only_fg,
|
||||
GError **error)
|
||||
{
|
||||
GHashTable *options;
|
||||
GdkTexture *texture;
|
||||
|
||||
if (!gdk_is_png (bytes))
|
||||
return gdk_texture_new_from_bytes (bytes, error);
|
||||
|
||||
options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
texture = gdk_load_png (bytes, options, error);
|
||||
*only_fg = g_hash_table_contains (options, "foreground-only");
|
||||
g_hash_table_unref (options);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
GdkTexture *
|
||||
gdk_texture_new_from_filename_with_fg (const char *filename,
|
||||
gboolean *only_fg,
|
||||
GError **error)
|
||||
{
|
||||
GFile *file;
|
||||
GBytes *bytes;
|
||||
GdkTexture *texture = NULL;
|
||||
|
||||
file = g_file_new_for_path (filename);
|
||||
bytes = g_file_load_bytes (file, NULL, NULL, error);
|
||||
if (bytes)
|
||||
texture = texture_new_from_bytes (bytes, only_fg, error);
|
||||
g_bytes_unref (bytes);
|
||||
g_object_unref (file);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
GdkTexture *
|
||||
gdk_texture_new_from_resource_with_fg (const char *path,
|
||||
gboolean *only_fg)
|
||||
{
|
||||
GBytes *bytes;
|
||||
GdkTexture *texture = NULL;
|
||||
|
||||
bytes = g_resources_lookup_data (path, 0, NULL);
|
||||
if (bytes)
|
||||
texture = texture_new_from_bytes (bytes, only_fg, NULL);
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
GdkTexture *
|
||||
gdk_texture_new_from_stream_at_scale (GInputStream *stream,
|
||||
int width,
|
||||
int height,
|
||||
gboolean aspect,
|
||||
gboolean *only_fg,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
@ -472,6 +544,7 @@ gdk_texture_new_from_stream_at_scale (GInputStream *stream,
|
||||
pixbuf = _gdk_pixbuf_new_from_stream_at_scale (stream, width, height, aspect, cancellable, error);
|
||||
if (pixbuf)
|
||||
{
|
||||
*only_fg = pixbuf_is_only_fg (pixbuf);
|
||||
texture = gdk_texture_new_for_pixbuf (pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
}
|
||||
@ -481,6 +554,7 @@ gdk_texture_new_from_stream_at_scale (GInputStream *stream,
|
||||
|
||||
GdkTexture *
|
||||
gdk_texture_new_from_stream (GInputStream *stream,
|
||||
gboolean *only_fg,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
@ -490,6 +564,7 @@ gdk_texture_new_from_stream (GInputStream *stream,
|
||||
pixbuf = _gdk_pixbuf_new_from_stream_scaled (stream, 0, cancellable, error);
|
||||
if (pixbuf)
|
||||
{
|
||||
*only_fg = pixbuf_is_only_fg (pixbuf);
|
||||
texture = gdk_texture_new_for_pixbuf (pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
}
|
||||
@ -502,6 +577,7 @@ gdk_texture_new_from_resource_at_scale (const char *path,
|
||||
int width,
|
||||
int height,
|
||||
gboolean preserve_aspect,
|
||||
gboolean *only_fg,
|
||||
GError **error)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
@ -510,6 +586,7 @@ gdk_texture_new_from_resource_at_scale (const char *path,
|
||||
pixbuf = _gdk_pixbuf_new_from_resource_at_scale (path, width, height, preserve_aspect, error);
|
||||
if (pixbuf)
|
||||
{
|
||||
*only_fg = pixbuf_is_only_fg (pixbuf);
|
||||
texture = gdk_texture_new_for_pixbuf (pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
}
|
||||
@ -525,6 +602,7 @@ gdk_texture_new_from_path_symbolic (const char *path,
|
||||
int width,
|
||||
int height,
|
||||
double scale,
|
||||
gboolean *only_fg,
|
||||
GError **error)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
@ -533,6 +611,7 @@ gdk_texture_new_from_path_symbolic (const char *path,
|
||||
pixbuf = make_symbolic_pixbuf_from_path (path, width, height, scale, error);
|
||||
if (pixbuf)
|
||||
{
|
||||
*only_fg = pixbuf_is_only_fg (pixbuf);
|
||||
texture = gdk_texture_new_for_pixbuf (pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
}
|
||||
@ -551,6 +630,7 @@ gdk_texture_new_from_resource_symbolic (const char *path,
|
||||
int width,
|
||||
int height,
|
||||
double scale,
|
||||
gboolean *only_fg,
|
||||
GError **error)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
@ -559,6 +639,7 @@ gdk_texture_new_from_resource_symbolic (const char *path,
|
||||
pixbuf = make_symbolic_pixbuf_from_resource (path, width, height, scale, error);
|
||||
if (pixbuf)
|
||||
{
|
||||
*only_fg = pixbuf_is_only_fg (pixbuf);
|
||||
texture = gdk_texture_new_for_pixbuf (pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
}
|
||||
@ -593,14 +674,19 @@ gdk_texture_new_from_file_symbolic (GFile *file,
|
||||
int width,
|
||||
int height,
|
||||
double scale,
|
||||
gboolean *only_fg,
|
||||
GError **error)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
GdkTexture *texture;
|
||||
GdkTexture *texture = NULL;
|
||||
|
||||
pixbuf = make_symbolic_pixbuf_from_file (file, width, height, scale, error);
|
||||
texture = gdk_texture_new_for_pixbuf (pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
if (pixbuf)
|
||||
{
|
||||
*only_fg = pixbuf_is_only_fg (pixbuf);
|
||||
texture = gdk_texture_new_for_pixbuf (pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
@ -29,35 +29,46 @@ GdkPixbuf *gtk_make_symbolic_pixbuf_from_data (const char *data,
|
||||
const char *debug_output_to,
|
||||
GError **error);
|
||||
|
||||
GdkTexture *gdk_texture_new_from_filename_with_fg (const char *filename,
|
||||
gboolean *only_fg,
|
||||
GError **error);
|
||||
GdkTexture *gdk_texture_new_from_resource_with_fg (const char *path,
|
||||
gboolean *only_fg);
|
||||
GdkTexture *gdk_texture_new_from_stream (GInputStream *stream,
|
||||
gboolean *only_fg,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
GdkTexture *gdk_texture_new_from_stream_at_scale (GInputStream *stream,
|
||||
int width,
|
||||
int height,
|
||||
gboolean aspect,
|
||||
gboolean *only_fg,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
GdkTexture *gdk_texture_new_from_resource_at_scale (const char *path,
|
||||
int width,
|
||||
int height,
|
||||
gboolean aspect,
|
||||
gboolean *only_fg,
|
||||
GError **error);
|
||||
|
||||
GdkTexture *gdk_texture_new_from_path_symbolic (const char *path,
|
||||
int width,
|
||||
int height,
|
||||
double scale,
|
||||
gboolean *only_fg,
|
||||
GError **error);
|
||||
GdkTexture *gdk_texture_new_from_file_symbolic (GFile *file,
|
||||
int width,
|
||||
int height,
|
||||
double scale,
|
||||
gboolean *only_fg,
|
||||
GError **error);
|
||||
GdkTexture *gdk_texture_new_from_resource_symbolic (const char *path,
|
||||
int width,
|
||||
int height,
|
||||
double scale,
|
||||
gboolean *only_fg,
|
||||
GError **error);
|
||||
|
||||
GdkTexture *gtk_load_symbolic_texture_from_file (GFile *file);
|
||||
|
@ -97,6 +97,7 @@ gtk_css_image_recolor_load_texture (GtkCssImageRecolor *recolor,
|
||||
GError **error)
|
||||
{
|
||||
char *uri;
|
||||
gboolean only_fg;
|
||||
|
||||
if (recolor->texture)
|
||||
return;
|
||||
@ -110,7 +111,7 @@ gtk_css_image_recolor_load_texture (GtkCssImageRecolor *recolor,
|
||||
if (g_str_has_suffix (uri, ".symbolic.png"))
|
||||
recolor->texture = gtk_load_symbolic_texture_from_resource (resource_path);
|
||||
else
|
||||
recolor->texture = gdk_texture_new_from_resource_symbolic (resource_path, 0, 0, 1.0, NULL);
|
||||
recolor->texture = gdk_texture_new_from_resource_symbolic (resource_path, 0, 0, 1.0, &only_fg, NULL);
|
||||
|
||||
g_free (resource_path);
|
||||
}
|
||||
@ -119,7 +120,7 @@ gtk_css_image_recolor_load_texture (GtkCssImageRecolor *recolor,
|
||||
if (g_str_has_suffix (uri, ".symbolic.png"))
|
||||
recolor->texture = gtk_load_symbolic_texture_from_file (recolor->file);
|
||||
else
|
||||
recolor->texture = gdk_texture_new_from_file_symbolic (recolor->file, 0, 0, 1.0, NULL);
|
||||
recolor->texture = gdk_texture_new_from_file_symbolic (recolor->file, 0, 0, 1.0, &only_fg, NULL);
|
||||
}
|
||||
|
||||
g_free (uri);
|
||||
|
@ -414,6 +414,7 @@ struct _GtkIconPaintable
|
||||
guint is_svg : 1;
|
||||
guint is_resource : 1;
|
||||
guint is_symbolic : 1;
|
||||
guint only_fg : 1;
|
||||
|
||||
/* Cached information if we go ahead and try to load the icon.
|
||||
*
|
||||
@ -3712,6 +3713,7 @@ icon_ensure_texture__locked (GtkIconPaintable *icon,
|
||||
gint64 before;
|
||||
int pixel_size;
|
||||
GError *load_error = NULL;
|
||||
gboolean only_fg = FALSE;
|
||||
|
||||
icon_cache_mark_used_if_cached (icon);
|
||||
|
||||
@ -3739,27 +3741,31 @@ icon_ensure_texture__locked (GtkIconPaintable *icon,
|
||||
{
|
||||
if (icon->is_svg)
|
||||
{
|
||||
if (gtk_icon_paintable_is_symbolic (icon))
|
||||
if (icon->is_symbolic)
|
||||
icon->texture = gdk_texture_new_from_resource_symbolic (icon->filename,
|
||||
pixel_size, pixel_size,
|
||||
icon->desired_scale,
|
||||
&only_fg,
|
||||
&load_error);
|
||||
else
|
||||
icon->texture = gdk_texture_new_from_resource_at_scale (icon->filename,
|
||||
pixel_size, pixel_size,
|
||||
TRUE, &load_error);
|
||||
TRUE,
|
||||
&only_fg,
|
||||
&load_error);
|
||||
}
|
||||
else
|
||||
icon->texture = gdk_texture_new_from_resource (icon->filename);
|
||||
icon->texture = gdk_texture_new_from_resource_with_fg (icon->filename, &only_fg);
|
||||
}
|
||||
else if (icon->filename)
|
||||
{
|
||||
if (icon->is_svg)
|
||||
{
|
||||
if (gtk_icon_paintable_is_symbolic (icon))
|
||||
if (icon->is_symbolic)
|
||||
icon->texture = gdk_texture_new_from_path_symbolic (icon->filename,
|
||||
pixel_size, pixel_size,
|
||||
icon->desired_scale,
|
||||
&only_fg,
|
||||
&load_error);
|
||||
else
|
||||
{
|
||||
@ -3770,7 +3776,9 @@ icon_ensure_texture__locked (GtkIconPaintable *icon,
|
||||
{
|
||||
icon->texture = gdk_texture_new_from_stream_at_scale (stream,
|
||||
pixel_size, pixel_size,
|
||||
TRUE, NULL,
|
||||
TRUE,
|
||||
&only_fg,
|
||||
NULL,
|
||||
&load_error);
|
||||
g_object_unref (stream);
|
||||
}
|
||||
@ -3780,7 +3788,7 @@ icon_ensure_texture__locked (GtkIconPaintable *icon,
|
||||
}
|
||||
else
|
||||
{
|
||||
icon->texture = gdk_texture_new_from_filename (icon->filename, &load_error);
|
||||
icon->texture = gdk_texture_new_from_filename_with_fg (icon->filename, &only_fg, &load_error);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -3798,15 +3806,19 @@ icon_ensure_texture__locked (GtkIconPaintable *icon,
|
||||
if (icon->is_svg)
|
||||
icon->texture = gdk_texture_new_from_stream_at_scale (stream,
|
||||
pixel_size, pixel_size,
|
||||
TRUE, NULL,
|
||||
TRUE,
|
||||
&only_fg,
|
||||
NULL,
|
||||
&load_error);
|
||||
else
|
||||
icon->texture = gdk_texture_new_from_stream (stream, NULL, &load_error);
|
||||
icon->texture = gdk_texture_new_from_stream (stream, &only_fg, NULL, &load_error);
|
||||
|
||||
g_object_unref (stream);
|
||||
}
|
||||
}
|
||||
|
||||
icon->only_fg = only_fg;
|
||||
|
||||
if (!icon->texture)
|
||||
{
|
||||
g_warning ("Failed to load icon %s: %s", icon->filename, load_error ? load_error->message : "");
|
||||
@ -3814,6 +3826,7 @@ icon_ensure_texture__locked (GtkIconPaintable *icon,
|
||||
icon->texture = gdk_texture_new_from_resource (IMAGE_MISSING_RESOURCE_PATH);
|
||||
icon->icon_name = g_strdup ("image-missing");
|
||||
icon->is_symbolic = FALSE;
|
||||
icon->only_fg = FALSE;
|
||||
}
|
||||
|
||||
if (GDK_PROFILER_IS_RUNNING)
|
||||
@ -3896,22 +3909,9 @@ gtk_icon_paintable_snapshot_symbolic (GtkSymbolicPaintable *paintable,
|
||||
int texture_width, texture_height;
|
||||
double render_width;
|
||||
double render_height;
|
||||
gboolean symbolic;
|
||||
graphene_rect_t render_rect;
|
||||
|
||||
texture = gtk_icon_paintable_ensure_texture (icon);
|
||||
symbolic = gtk_icon_paintable_is_symbolic (icon);
|
||||
|
||||
if (symbolic)
|
||||
{
|
||||
graphene_matrix_t matrix;
|
||||
graphene_vec4_t offset;
|
||||
|
||||
init_color_matrix (&matrix, &offset,
|
||||
&colors[0], &colors[3],
|
||||
&colors[2], &colors[1]);
|
||||
|
||||
gtk_snapshot_push_color_matrix (snapshot, &matrix, &offset);
|
||||
}
|
||||
|
||||
texture_width = gdk_texture_get_width (texture);
|
||||
texture_height = gdk_texture_get_height (texture);
|
||||
@ -3928,14 +3928,39 @@ gtk_icon_paintable_snapshot_symbolic (GtkSymbolicPaintable *paintable,
|
||||
render_height = height;
|
||||
}
|
||||
|
||||
gtk_snapshot_append_texture (snapshot, texture,
|
||||
&GRAPHENE_RECT_INIT ((width - render_width) / 2,
|
||||
(height - render_height) / 2,
|
||||
render_width,
|
||||
render_height));
|
||||
graphene_rect_init (&render_rect,
|
||||
(width - render_width) / 2,
|
||||
(height - render_height) / 2,
|
||||
render_width,
|
||||
render_height);
|
||||
|
||||
if (symbolic)
|
||||
gtk_snapshot_pop (snapshot);
|
||||
if (icon->is_symbolic && icon->only_fg)
|
||||
{
|
||||
g_debug ("snapshot symbolic icon using mask");
|
||||
gtk_snapshot_push_mask (snapshot, GSK_MASK_MODE_ALPHA);
|
||||
gtk_snapshot_append_texture (snapshot, texture, &render_rect);
|
||||
gtk_snapshot_pop (snapshot);
|
||||
gtk_snapshot_append_color (snapshot, &colors[0], &render_rect);
|
||||
gtk_snapshot_pop (snapshot);
|
||||
}
|
||||
else if (icon->is_symbolic)
|
||||
{
|
||||
graphene_matrix_t matrix;
|
||||
graphene_vec4_t offset;
|
||||
|
||||
g_debug ("snapshot symbolic icon using color-matrix");
|
||||
init_color_matrix (&matrix, &offset,
|
||||
&colors[0], &colors[3],
|
||||
&colors[2], &colors[1]);
|
||||
|
||||
gtk_snapshot_push_color_matrix (snapshot, &matrix, &offset);
|
||||
gtk_snapshot_append_texture (snapshot, texture, &render_rect);
|
||||
gtk_snapshot_pop (snapshot);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_snapshot_append_texture (snapshot, texture, &render_rect);
|
||||
}
|
||||
}
|
||||
|
||||
static GdkPaintableFlags
|
||||
|
@ -56,6 +56,9 @@ main (int argc, char **argv)
|
||||
GFile *dest;
|
||||
char *data;
|
||||
gsize len;
|
||||
GHashTable *options;
|
||||
GPtrArray *keys;
|
||||
GPtrArray *values;
|
||||
|
||||
setlocale (LC_ALL, "");
|
||||
|
||||
@ -142,7 +145,19 @@ main (int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!gdk_pixbuf_save_to_stream (symbolic, G_OUTPUT_STREAM (out), "png", NULL, &error, NULL))
|
||||
options = gdk_pixbuf_get_options (symbolic);
|
||||
keys = g_hash_table_get_keys_as_ptr_array (options);
|
||||
values = g_hash_table_get_values_as_ptr_array (options);
|
||||
g_ptr_array_add (keys, NULL);
|
||||
g_ptr_array_add (values, NULL);
|
||||
|
||||
if (!gdk_pixbuf_save_to_streamv (symbolic,
|
||||
G_OUTPUT_STREAM (out),
|
||||
"png",
|
||||
(char **) keys->pdata,
|
||||
(char **) values->pdata,
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_printerr (_("Can’t save file %s: %s\n"), pngpath, error->message);
|
||||
return 1;
|
||||
@ -154,6 +169,10 @@ main (int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_ptr_array_unref (keys);
|
||||
g_ptr_array_unref (values);
|
||||
g_hash_table_unref (options);
|
||||
|
||||
g_object_unref (out);
|
||||
g_free (pngpath);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user