gtk2/gtk/gtkcssimageurl.c
Benjamin Otte 6348ded15d cssimage: Store the URI we're loaded from
I'd like to use it when printing the value, but I haven't found a way to
do that sanely yet, as I'd need to be able to print relative paths for
make check to work (otherwise the srcdir would blow things up). And we
use a GString to output to, so there's no way to attach a base dir to
that.

If anyone has an idea how to achieve that, poke me. Having the real
filename in debug prints sounds like a very good idea to me.

https://bugzilla.gnome.org/show_bug.cgi?id=692934
2013-02-02 01:42:48 +01:00

190 lines
5.2 KiB
C

/*
* Copyright © 2011 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include <string.h>
#include "gtkcssimageurlprivate.h"
#include "gtkcssprovider.h"
G_DEFINE_TYPE (GtkCssImageUrl, _gtk_css_image_url, GTK_TYPE_CSS_IMAGE)
static int
gtk_css_image_url_get_width (GtkCssImage *image)
{
GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (image);
return cairo_image_surface_get_width (url->surface);
}
static int
gtk_css_image_url_get_height (GtkCssImage *image)
{
GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (image);
return cairo_image_surface_get_height (url->surface);
}
static void
gtk_css_image_url_draw (GtkCssImage *image,
cairo_t *cr,
double width,
double height)
{
GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (image);
cairo_rectangle (cr, 0, 0, width, height);
cairo_scale (cr,
width / cairo_image_surface_get_width (url->surface),
height / cairo_image_surface_get_height (url->surface));
cairo_set_source_surface (cr, url->surface, 0, 0);
cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD);
cairo_fill (cr);
}
static gboolean
gtk_css_image_url_parse (GtkCssImage *image,
GtkCssParser *parser)
{
GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (image);
GdkPixbuf *pixbuf;
cairo_t *cr;
GError *error = NULL;
GFileInputStream *input;
url->file = _gtk_css_parser_read_url (parser);
if (url->file == NULL)
return FALSE;
/* We special case resources here so we can use
gdk_pixbuf_new_from_resource, which in turn has some special casing
for GdkPixdata files to avoid duplicating the memory for the pixbufs */
if (g_file_has_uri_scheme (url->file, "resource"))
{
char *uri = g_file_get_uri (url->file);
char *resource_path = g_uri_unescape_string (uri + strlen ("resource://"), NULL);
pixbuf = gdk_pixbuf_new_from_resource (resource_path, &error);
g_free (resource_path);
g_free (uri);
}
else
{
input = g_file_read (url->file, NULL, &error);
if (input == NULL)
{
_gtk_css_parser_take_error (parser, error);
return FALSE;
}
pixbuf = gdk_pixbuf_new_from_stream (G_INPUT_STREAM (input), NULL, &error);
g_object_unref (input);
}
if (pixbuf == NULL)
{
_gtk_css_parser_take_error (parser, error);
return FALSE;
}
url->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf));
cr = cairo_create (url->surface);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_paint (cr);
cairo_destroy (cr);
g_object_unref (pixbuf);
return TRUE;
}
static cairo_status_t
surface_write (void *closure,
const unsigned char *data,
unsigned int length)
{
g_byte_array_append (closure, data, length);
return CAIRO_STATUS_SUCCESS;
}
static void
gtk_css_image_url_print (GtkCssImage *image,
GString *string)
{
#if CAIRO_HAS_PNG_FUNCTIONS
GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (image);
GByteArray *array;
char *base64;
array = g_byte_array_new ();
cairo_surface_write_to_png_stream (url->surface, surface_write, array);
base64 = g_base64_encode (array->data, array->len);
g_byte_array_free (array, TRUE);
g_string_append (string, "url(\"data:image/png;base64,");
g_string_append (string, base64);
g_string_append (string, "\")");
g_free (base64);
#else
g_string_append (string, "none /* you need cairo png functions enabled to make this work */");
#endif
}
static void
gtk_css_image_url_dispose (GObject *object)
{
GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (object);
g_clear_object (&url->file);
if (url->surface)
{
cairo_surface_destroy (url->surface);
url->surface = NULL;
}
G_OBJECT_CLASS (_gtk_css_image_url_parent_class)->dispose (object);
}
static void
_gtk_css_image_url_class_init (GtkCssImageUrlClass *klass)
{
GtkCssImageClass *image_class = GTK_CSS_IMAGE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
image_class->get_width = gtk_css_image_url_get_width;
image_class->get_height = gtk_css_image_url_get_height;
image_class->draw = gtk_css_image_url_draw;
image_class->parse = gtk_css_image_url_parse;
image_class->print = gtk_css_image_url_print;
object_class->dispose = gtk_css_image_url_dispose;
}
static void
_gtk_css_image_url_init (GtkCssImageUrl *image_url)
{
}