1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2011 Red Hat, Inc.
4 * Author: Cosimo Cecchi <cosimoc@gnome.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
22 #include "gtkcssshadowvalueprivate.h"
24 #include "gtkstylecontextprivate.h"
25 #include "gtkthemingengineprivate.h"
28 typedef struct _GtkShadowElement GtkShadowElement;
30 struct _GtkShadowElement {
39 GtkSymbolicColor *symbolic_color;
43 shadow_element_print (GtkShadowElement *element,
49 g_string_append (str, "inset ");
51 g_string_append_printf (str, "%d %d ",
52 (gint) element->hoffset,
53 (gint) element->voffset);
55 if (element->radius != 0)
56 g_string_append_printf (str, "%d ", (gint) element->radius);
58 if (element->spread != 0)
59 g_string_append_printf (str, "%d ", (gint) element->spread);
61 if (element->symbolic_color != NULL)
62 color_str = gtk_symbolic_color_to_string (element->symbolic_color);
64 color_str = gdk_rgba_to_string (&element->color);
66 g_string_append (str, color_str);
71 shadow_element_free (GtkShadowElement *element)
73 if (element->symbolic_color != NULL)
74 gtk_symbolic_color_unref (element->symbolic_color);
76 g_slice_free (GtkShadowElement, element);
79 static GtkShadowElement *
80 shadow_element_new (gdouble hoffset,
86 GtkSymbolicColor *symbolic_color)
88 GtkShadowElement *retval;
90 retval = g_slice_new0 (GtkShadowElement);
92 retval->hoffset = hoffset;
93 retval->voffset = voffset;
94 retval->radius = radius;
95 retval->spread = spread;
96 retval->inset = inset;
98 if (symbolic_color != NULL)
99 retval->symbolic_color = gtk_symbolic_color_ref (symbolic_color);
102 retval->color = *color;
111 struct _GtkCssValue {
117 gtk_css_value_shadow_free (GtkCssValue *shadow)
119 g_list_free_full (shadow->elements,
120 (GDestroyNotify) shadow_element_free);
121 g_slice_free (GtkCssValue, shadow);
125 gtk_css_value_shadow_equal (const GtkCssValue *shadow1,
126 const GtkCssValue *shadow2)
129 return shadow1 == shadow2;
133 gtk_css_value_shadow_transition (GtkCssValue *start,
141 gtk_css_value_shadow_print (const GtkCssValue *shadow,
147 length = g_list_length (shadow->elements);
151 g_string_append (string, "none");
155 shadow_element_print (shadow->elements->data, string);
160 for (l = g_list_next (shadow->elements); l != NULL; l = l->next)
162 g_string_append (string, ", ");
163 shadow_element_print (l->data, string);
167 static const GtkCssValueClass GTK_CSS_VALUE_SHADOW = {
168 gtk_css_value_shadow_free,
169 gtk_css_value_shadow_equal,
170 gtk_css_value_shadow_transition,
171 gtk_css_value_shadow_print
174 static GtkCssValue none_singleton = { >K_CSS_VALUE_SHADOW, 1, NULL };
177 _gtk_css_shadow_value_new_none (void)
179 return _gtk_css_value_ref (&none_singleton);
183 _gtk_css_shadow_value_parse (GtkCssParser *parser)
185 gboolean have_inset, have_color, have_lengths;
186 gdouble hoffset, voffset, blur, spread;
187 GtkSymbolicColor *color;
188 GtkShadowElement *element;
192 if (_gtk_css_parser_try (parser, "none", TRUE))
193 return _gtk_css_shadow_value_new_none ();
195 shadow = _gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_SHADOW);
199 have_inset = have_lengths = have_color = FALSE;
201 for (i = 0; i < 3; i++)
204 _gtk_css_parser_try (parser, "inset", TRUE))
211 _gtk_css_parser_try_double (parser, &hoffset))
215 if (!_gtk_css_parser_try_double (parser, &voffset))
217 _gtk_css_parser_error (parser, "Horizontal and vertical offsets are required");
218 _gtk_css_value_unref (shadow);
222 if (!_gtk_css_parser_try_double (parser, &blur))
225 if (!_gtk_css_parser_try_double (parser, &spread))
235 /* XXX: the color is optional and UA-defined if it's missing,
236 * but it doesn't really make sense for us...
238 color = _gtk_css_parser_read_symbolic_color (parser);
242 _gtk_css_value_unref (shadow);
248 if (!have_color || !have_lengths)
250 _gtk_css_parser_error (parser, "Must specify at least color and offsets");
251 _gtk_css_value_unref (shadow);
255 element = shadow_element_new (hoffset, voffset,
256 blur, spread, have_inset,
259 shadow->elements = g_list_append (shadow->elements, element);
261 gtk_symbolic_color_unref (color);
264 while (_gtk_css_parser_try (parser, ",", TRUE));
270 _gtk_css_shadow_value_compute (GtkCssValue *shadow,
271 GtkStyleContext *context)
273 GtkCssValue *resolved_shadow;
274 GtkShadowElement *element, *resolved_element;
278 resolved_shadow = _gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_SHADOW);
280 for (l = shadow->elements; l != NULL; l = l->next)
284 if (!_gtk_style_context_resolve_color (context,
285 element->symbolic_color,
288 _gtk_css_value_unref (resolved_shadow);
293 shadow_element_new (element->hoffset, element->voffset,
294 element->radius, element->spread, element->inset,
297 resolved_shadow->elements =
298 g_list_append (resolved_shadow->elements, resolved_element);
301 return resolved_shadow;
305 _gtk_css_shadow_value_paint_layout (const GtkCssValue *shadow,
310 GtkShadowElement *element;
312 if (!cairo_has_current_point (cr))
313 cairo_move_to (cr, 0, 0);
315 /* render shadows starting from the last one,
316 * and the others on top.
318 for (l = g_list_last (shadow->elements); l != NULL; l = l->prev)
324 cairo_rel_move_to (cr, element->hoffset, element->voffset);
325 gdk_cairo_set_source_rgba (cr, &element->color);
326 _gtk_pango_fill_layout (cr, layout);
328 cairo_rel_move_to (cr, -element->hoffset, -element->voffset);
334 _gtk_css_shadow_value_paint_icon (const GtkCssValue *shadow,
338 GtkShadowElement *element;
339 cairo_pattern_t *pattern;
341 for (l = g_list_last (shadow->elements); l != NULL; l = l->prev)
346 pattern = cairo_pattern_reference (cairo_get_source (cr));
347 gdk_cairo_set_source_rgba (cr, &element->color);
349 cairo_translate (cr, element->hoffset, element->voffset);
350 cairo_mask (cr, pattern);
353 cairo_pattern_destroy (pattern);
358 _gtk_css_shadow_value_paint_spinner (const GtkCssValue *shadow,
363 GtkShadowElement *element;
366 for (l = g_list_last (shadow->elements); l != NULL; l = l->prev)
372 cairo_translate (cr, element->hoffset, element->voffset);
373 _gtk_theming_engine_paint_spinner (cr,
382 _gtk_css_shadow_value_paint_box (const GtkCssValue *shadow,
384 const GtkRoundedBox *padding_box)
386 GtkShadowElement *element;
391 cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
393 _gtk_rounded_box_path (padding_box, cr);
396 /* render shadows starting from the last one,
397 * and the others on top.
399 for (l = g_list_last (shadow->elements); l != NULL; l = l->prev)
407 _gtk_rounded_box_move (&box, element->hoffset, element->voffset);
408 _gtk_rounded_box_shrink (&box,
409 element->spread, element->spread,
410 element->spread, element->spread);
412 _gtk_rounded_box_path (&box, cr);
413 _gtk_rounded_box_clip_path (padding_box, cr);
415 gdk_cairo_set_source_rgba (cr, &element->color);