1/*
2 * Copyright © 2011 Red Hat Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Benjamin Otte <otte@gnome.org>
18 */
19
20#include "config.h"
21
22#include <string.h>
23
24#include "gtkcssimageurlprivate.h"
25
26#include "gtkcssimageinvalidprivate.h"
27#include "gtkcssimagepaintableprivate.h"
28#include "gtkstyleproviderprivate.h"
29#include "gtk/css/gtkcssdataurlprivate.h"
30
31
32G_DEFINE_TYPE (GtkCssImageUrl, _gtk_css_image_url, GTK_TYPE_CSS_IMAGE)
33
34static GtkCssImage *
35gtk_css_image_url_load_image (GtkCssImageUrl *url,
36 GError **error)
37{
38 GdkTexture *texture;
39 GError *local_error = NULL;
40
41 if (url->loaded_image)
42 return url->loaded_image;
43
44 if (url->file == NULL)
45 {
46 url->loaded_image = gtk_css_image_invalid_new ();
47 return url->loaded_image;
48 }
49
50 /* We special case resources here so we can use gdk_texture_new_from_resource. */
51 if (g_file_has_uri_scheme (file: url->file, uri_scheme: "resource"))
52 {
53 char *uri = g_file_get_uri (file: url->file);
54 char *resource_path = g_uri_unescape_string (escaped_string: uri + strlen (s: "resource://"), NULL);
55
56 texture = gdk_texture_new_from_resource (resource_path);
57
58 g_free (mem: resource_path);
59 g_free (mem: uri);
60 }
61 else
62 {
63 texture = gdk_texture_new_from_file (file: url->file, error: &local_error);
64 }
65
66 if (texture == NULL)
67 {
68 if (error && local_error)
69 {
70 char *uri;
71
72 uri = g_file_get_uri (file: url->file);
73 g_set_error (err: error,
74 GTK_CSS_PARSER_ERROR,
75 code: GTK_CSS_PARSER_ERROR_FAILED,
76 format: "Error loading image '%s': %s", uri, local_error->message);
77 g_free (mem: uri);
78 }
79
80 url->loaded_image = gtk_css_image_invalid_new ();
81 }
82 else
83 {
84 url->loaded_image = gtk_css_image_paintable_new (paintable: GDK_PAINTABLE (ptr: texture), static_paintable: GDK_PAINTABLE (ptr: texture));
85 g_object_unref (object: texture);
86 }
87
88 g_clear_error (err: &local_error);
89
90 return url->loaded_image;
91}
92
93static int
94gtk_css_image_url_get_width (GtkCssImage *image)
95{
96 GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (image);
97
98 return _gtk_css_image_get_width (image: gtk_css_image_url_load_image (url, NULL));
99}
100
101static int
102gtk_css_image_url_get_height (GtkCssImage *image)
103{
104 GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (image);
105
106 return _gtk_css_image_get_height (image: gtk_css_image_url_load_image (url, NULL));
107}
108
109static double
110gtk_css_image_url_get_aspect_ratio (GtkCssImage *image)
111{
112 GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (image);
113
114 return _gtk_css_image_get_aspect_ratio (image: gtk_css_image_url_load_image (url, NULL));
115}
116
117static void
118gtk_css_image_url_snapshot (GtkCssImage *image,
119 GtkSnapshot *snapshot,
120 double width,
121 double height)
122{
123 GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (image);
124
125 gtk_css_image_snapshot (image: gtk_css_image_url_load_image (url, NULL), snapshot, width, height);
126}
127
128static GtkCssImage *
129gtk_css_image_url_compute (GtkCssImage *image,
130 guint property_id,
131 GtkStyleProvider *provider,
132 GtkCssStyle *style,
133 GtkCssStyle *parent_style)
134{
135 GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (image);
136 GtkCssImage *copy;
137 GError *error = NULL;
138
139 copy = gtk_css_image_url_load_image (url, error: &error);
140 if (error)
141 {
142 GtkCssSection *section = gtk_css_style_get_section (style, id: property_id);
143 gtk_style_provider_emit_error (provider, section, error);
144 g_error_free (error);
145 }
146
147 return g_object_ref (copy);
148}
149
150static gboolean
151gtk_css_image_url_equal (GtkCssImage *image1,
152 GtkCssImage *image2)
153{
154 GtkCssImageUrl *url1 = GTK_CSS_IMAGE_URL (image1);
155 GtkCssImageUrl *url2 = GTK_CSS_IMAGE_URL (image2);
156
157 /* FIXME: We don't save data: urls, so we can't compare them here */
158 if (url1->file == NULL || url2->file == NULL)
159 return FALSE;
160
161 return g_file_equal (file1: url1->file, file2: url2->file);
162}
163
164static gboolean
165gtk_css_image_url_is_invalid (GtkCssImage *image)
166{
167 GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (image);
168
169 return gtk_css_image_is_invalid (image: gtk_css_image_url_load_image (url, NULL));
170}
171
172static gboolean
173gtk_css_image_url_is_computed (GtkCssImage *image)
174{
175 return TRUE;
176}
177
178static gboolean
179gtk_css_image_url_parse (GtkCssImage *image,
180 GtkCssParser *parser)
181{
182 GtkCssImageUrl *self = GTK_CSS_IMAGE_URL (image);
183 char *url, *scheme;
184
185 url = gtk_css_parser_consume_url (self: parser);
186 if (url == NULL)
187 return FALSE;
188
189 scheme = g_uri_parse_scheme (uri: url);
190 if (scheme && g_ascii_strcasecmp (s1: scheme, s2: "data") == 0)
191 {
192 GBytes *bytes;
193 GError *error = NULL;
194
195 bytes = gtk_css_data_url_parse (url, NULL, error: &error);
196 if (bytes)
197 {
198 GdkTexture *texture;
199
200 texture = gdk_texture_new_from_bytes (bytes, error: &error);
201 g_bytes_unref (bytes);
202 if (texture)
203 {
204 GdkPaintable *paintable = GDK_PAINTABLE (ptr: texture);
205 self->loaded_image = gtk_css_image_paintable_new (paintable, static_paintable: paintable);
206 }
207 else
208 {
209 gtk_css_parser_emit_error (self: parser,
210 start: gtk_css_parser_get_start_location (self: parser),
211 end: gtk_css_parser_get_end_location (self: parser),
212 error);
213 g_clear_error (err: &error);
214 }
215 }
216 else
217 {
218 gtk_css_parser_emit_error (self: parser,
219 start: gtk_css_parser_get_start_location (self: parser),
220 end: gtk_css_parser_get_end_location (self: parser),
221 error);
222 g_clear_error (err: &error);
223 }
224 }
225 else
226 {
227 self->file = gtk_css_parser_resolve_url (self: parser, url);
228 }
229
230 g_free (mem: url);
231 g_free (mem: scheme);
232
233 return TRUE;
234}
235
236static void
237gtk_css_image_url_print (GtkCssImage *image,
238 GString *string)
239{
240 GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (image);
241
242 _gtk_css_image_print (image: gtk_css_image_url_load_image (url, NULL), string);
243}
244
245static void
246gtk_css_image_url_dispose (GObject *object)
247{
248 GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (object);
249
250 g_clear_object (&url->file);
251 g_clear_object (&url->loaded_image);
252
253 G_OBJECT_CLASS (_gtk_css_image_url_parent_class)->dispose (object);
254}
255
256static void
257_gtk_css_image_url_class_init (GtkCssImageUrlClass *klass)
258{
259 GtkCssImageClass *image_class = GTK_CSS_IMAGE_CLASS (klass);
260 GObjectClass *object_class = G_OBJECT_CLASS (klass);
261
262 image_class->get_width = gtk_css_image_url_get_width;
263 image_class->get_height = gtk_css_image_url_get_height;
264 image_class->get_aspect_ratio = gtk_css_image_url_get_aspect_ratio;
265 image_class->compute = gtk_css_image_url_compute;
266 image_class->snapshot = gtk_css_image_url_snapshot;
267 image_class->parse = gtk_css_image_url_parse;
268 image_class->print = gtk_css_image_url_print;
269 image_class->equal = gtk_css_image_url_equal;
270 image_class->is_invalid = gtk_css_image_url_is_invalid;
271 image_class->is_computed = gtk_css_image_url_is_computed;
272
273 object_class->dispose = gtk_css_image_url_dispose;
274}
275
276static void
277_gtk_css_image_url_init (GtkCssImageUrl *image_url)
278{
279}
280
281

source code of gtk/gtk/gtkcssimageurl.c