2 * Copyright © 2011 Red Hat Inc.
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.
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.
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/>.
17 * Authors: Benjamin Otte <otte@gnome.org>
22 #include "gtkcssimagegradientprivate.h"
24 #include "gtkcssprovider.h"
25 #include "gtkgradientprivate.h"
26 #include "gtksymboliccolorprivate.h"
28 G_DEFINE_TYPE (GtkCssImageGradient, _gtk_css_image_gradient, GTK_TYPE_CSS_IMAGE)
31 gtk_css_image_gradient_compute (GtkCssImage *image,
33 GtkStyleProviderPrivate *provider,
34 GtkCssComputedValues *values,
35 GtkCssComputedValues *parent_values,
36 GtkCssDependencies *dependencies)
38 GtkCssImageGradient *gradient = GTK_CSS_IMAGE_GRADIENT (image);
39 GtkCssImageGradient *copy;
41 if (gradient->pattern)
42 return g_object_ref (gradient);
44 copy = g_object_new (GTK_TYPE_CSS_IMAGE_GRADIENT, NULL);
45 copy->gradient = gtk_gradient_ref (gradient->gradient);
46 copy->pattern = _gtk_gradient_resolve_full (copy->gradient, provider, values, parent_values, dependencies);
48 return GTK_CSS_IMAGE (copy);
52 gtk_css_image_gradient_draw_circle (GtkCssImageGradient *image,
57 cairo_pattern_t *pattern = image->pattern;
58 double x0, y0, x1, y1, r0, r1;
59 GdkRGBA color0, color1;
60 double offset0, offset1;
63 if (cairo_pattern_get_type (pattern) != CAIRO_PATTERN_TYPE_RADIAL)
65 if (cairo_pattern_get_extend (pattern) != CAIRO_EXTEND_PAD)
68 cairo_pattern_get_radial_circles (pattern, &x0, &y0, &r0, &x1, &y1, &r1);
75 cairo_pattern_get_color_stop_count (pattern, &n_stops);
79 cairo_pattern_get_color_stop_rgba (pattern, 0, &offset0, &color0.red, &color0.green, &color0.blue, &color0.alpha);
80 cairo_pattern_get_color_stop_rgba (pattern, 1, &offset1, &color1.red, &color1.green, &color1.blue, &color1.alpha);
81 if (offset0 != offset1)
84 cairo_scale (cr, width, height);
86 cairo_rectangle (cr, 0, 0, 1, 1);
89 gdk_cairo_set_source_rgba (cr, &color1);
92 gdk_cairo_set_source_rgba (cr, &color0);
93 cairo_arc (cr, x1, y1, r1 * offset1, 0, 2 * G_PI);
100 gtk_css_image_gradient_draw (GtkCssImage *image,
105 GtkCssImageGradient *gradient = GTK_CSS_IMAGE_GRADIENT (image);
107 if (!gradient->pattern)
109 g_warning ("trying to paint unresolved gradient");
113 if (gtk_css_image_gradient_draw_circle (gradient, cr, width, height))
116 cairo_scale (cr, width, height);
118 cairo_rectangle (cr, 0, 0, 1, 1);
119 cairo_set_source (cr, gradient->pattern);
124 gtk_css_image_gradient_parse (GtkCssImage *image,
125 GtkCssParser *parser)
127 GtkCssImageGradient *gradient = GTK_CSS_IMAGE_GRADIENT (image);
129 gradient->gradient = _gtk_gradient_parse (parser);
131 return gradient->gradient != NULL;
135 gtk_css_image_gradient_print (GtkCssImage *image,
138 GtkCssImageGradient *gradient = GTK_CSS_IMAGE_GRADIENT (image);
141 s = gtk_gradient_to_string (gradient->gradient);
142 g_string_append (string, s);
147 gtk_css_image_gradient_dispose (GObject *object)
149 GtkCssImageGradient *gradient = GTK_CSS_IMAGE_GRADIENT (object);
151 if (gradient->gradient)
153 gtk_gradient_unref (gradient->gradient);
154 gradient->gradient = NULL;
156 if (gradient->pattern)
158 cairo_pattern_destroy (gradient->pattern);
159 gradient->pattern = NULL;
162 G_OBJECT_CLASS (_gtk_css_image_gradient_parent_class)->dispose (object);
166 _gtk_css_image_gradient_class_init (GtkCssImageGradientClass *klass)
168 GtkCssImageClass *image_class = GTK_CSS_IMAGE_CLASS (klass);
169 GObjectClass *object_class = G_OBJECT_CLASS (klass);
171 image_class->compute = gtk_css_image_gradient_compute;
172 image_class->draw = gtk_css_image_gradient_draw;
173 image_class->parse = gtk_css_image_gradient_parse;
174 image_class->print = gtk_css_image_gradient_print;
176 object_class->dispose = gtk_css_image_gradient_dispose;
180 _gtk_css_image_gradient_init (GtkCssImageGradient *image_gradient)
185 _gtk_gradient_parse (GtkCssParser *parser)
187 GtkGradient *gradient;
188 cairo_pattern_type_t type;
192 g_return_val_if_fail (parser != NULL, NULL);
194 if (!_gtk_css_parser_try (parser, "-gtk-gradient", TRUE))
196 _gtk_css_parser_error (parser,
197 "Expected '-gtk-gradient'");
201 if (!_gtk_css_parser_try (parser, "(", TRUE))
203 _gtk_css_parser_error (parser,
204 "Expected '(' after '-gtk-gradient'");
208 /* Parse gradient type */
209 if (_gtk_css_parser_try (parser, "linear", TRUE))
210 type = CAIRO_PATTERN_TYPE_LINEAR;
211 else if (_gtk_css_parser_try (parser, "radial", TRUE))
212 type = CAIRO_PATTERN_TYPE_RADIAL;
215 _gtk_css_parser_error (parser,
216 "Gradient type must be 'radial' or 'linear'");
220 /* Parse start/stop position parameters */
221 for (i = 0; i < 2; i++)
223 if (! _gtk_css_parser_try (parser, ",", TRUE))
225 _gtk_css_parser_error (parser,
230 if (_gtk_css_parser_try (parser, "left", TRUE))
232 else if (_gtk_css_parser_try (parser, "right", TRUE))
234 else if (_gtk_css_parser_try (parser, "center", TRUE))
236 else if (!_gtk_css_parser_try_double (parser, &coords[i * 3]))
238 _gtk_css_parser_error (parser,
239 "Expected a valid X coordinate");
243 if (_gtk_css_parser_try (parser, "top", TRUE))
244 coords[i * 3 + 1] = 0;
245 else if (_gtk_css_parser_try (parser, "bottom", TRUE))
246 coords[i * 3 + 1] = 1;
247 else if (_gtk_css_parser_try (parser, "center", TRUE))
248 coords[i * 3 + 1] = 0.5;
249 else if (!_gtk_css_parser_try_double (parser, &coords[i * 3 + 1]))
251 _gtk_css_parser_error (parser,
252 "Expected a valid Y coordinate");
256 if (type == CAIRO_PATTERN_TYPE_RADIAL)
259 if (! _gtk_css_parser_try (parser, ",", TRUE))
261 _gtk_css_parser_error (parser,
266 if (! _gtk_css_parser_try_double (parser, &coords[(i * 3) + 2]))
268 _gtk_css_parser_error (parser,
269 "Expected a numer for the radius");
275 if (type == CAIRO_PATTERN_TYPE_LINEAR)
276 gradient = gtk_gradient_new_linear (coords[0], coords[1], coords[3], coords[4]);
278 gradient = gtk_gradient_new_radial (coords[0], coords[1], coords[2],
279 coords[3], coords[4], coords[5]);
281 while (_gtk_css_parser_try (parser, ",", TRUE))
283 GtkSymbolicColor *color;
286 if (_gtk_css_parser_try (parser, "from", TRUE))
290 if (!_gtk_css_parser_try (parser, "(", TRUE))
292 gtk_gradient_unref (gradient);
293 _gtk_css_parser_error (parser,
299 else if (_gtk_css_parser_try (parser, "to", TRUE))
303 if (!_gtk_css_parser_try (parser, "(", TRUE))
305 gtk_gradient_unref (gradient);
306 _gtk_css_parser_error (parser,
312 else if (_gtk_css_parser_try (parser, "color-stop", TRUE))
314 if (!_gtk_css_parser_try (parser, "(", TRUE))
316 gtk_gradient_unref (gradient);
317 _gtk_css_parser_error (parser,
322 if (!_gtk_css_parser_try_double (parser, &position))
324 gtk_gradient_unref (gradient);
325 _gtk_css_parser_error (parser,
326 "Expected a valid number");
330 if (!_gtk_css_parser_try (parser, ",", TRUE))
332 gtk_gradient_unref (gradient);
333 _gtk_css_parser_error (parser,
340 gtk_gradient_unref (gradient);
341 _gtk_css_parser_error (parser,
342 "Not a valid color-stop definition");
346 color = _gtk_symbolic_color_new_take_value (_gtk_css_symbolic_value_new (parser));
349 gtk_gradient_unref (gradient);
353 gtk_gradient_add_color_stop (gradient, position, color);
354 gtk_symbolic_color_unref (color);
356 if (!_gtk_css_parser_try (parser, ")", TRUE))
358 gtk_gradient_unref (gradient);
359 _gtk_css_parser_error (parser,
365 if (!_gtk_css_parser_try (parser, ")", TRUE))
367 gtk_gradient_unref (gradient);
368 _gtk_css_parser_error (parser,