#include "gtkcssshadowvalueprivate.h"
+#include "gtkcairoblurprivate.h"
+#include "gtkcsscolorvalueprivate.h"
#include "gtkcssnumbervalueprivate.h"
#include "gtkcssrgbavalueprivate.h"
#include "gtkstylecontextprivate.h"
-#include "gtksymboliccolorprivate.h"
#include "gtkthemingengineprivate.h"
#include "gtkpango.h"
GtkCssValue *color;
};
+static GtkCssValue * gtk_css_shadow_value_new (GtkCssValue *hoffset,
+ GtkCssValue *voffset,
+ GtkCssValue *radius,
+ GtkCssValue *spread,
+ gboolean inset,
+ GtkCssValue *color);
+
static void
gtk_css_value_shadow_free (GtkCssValue *shadow)
{
g_slice_free (GtkCssValue, shadow);
}
+static GtkCssValue *
+gtk_css_value_shadow_compute (GtkCssValue *shadow,
+ guint property_id,
+ GtkStyleProviderPrivate *provider,
+ GtkCssComputedValues *values,
+ GtkCssComputedValues *parent_values,
+ GtkCssDependencies *dependencies)
+{
+ GtkCssValue *hoffset, *voffset, *radius, *spread, *color;
+ GtkCssDependencies child_deps;
+
+ child_deps = 0;
+ hoffset = _gtk_css_value_compute (shadow->hoffset, property_id, provider, values, parent_values, &child_deps);
+ *dependencies = _gtk_css_dependencies_union (*dependencies, child_deps);
+
+ child_deps = 0;
+ voffset = _gtk_css_value_compute (shadow->voffset, property_id, provider, values, parent_values, &child_deps);
+ *dependencies = _gtk_css_dependencies_union (*dependencies, child_deps);
+
+ child_deps = 0;
+ radius = _gtk_css_value_compute (shadow->radius, property_id, provider, values, parent_values, &child_deps);
+ *dependencies = _gtk_css_dependencies_union (*dependencies, child_deps);
+
+ child_deps = 0;
+ spread = _gtk_css_value_compute (shadow->spread, property_id, provider, values, parent_values, &child_deps),
+ *dependencies = _gtk_css_dependencies_union (*dependencies, child_deps);
+
+ child_deps = 0;
+ color = _gtk_css_value_compute (shadow->color, property_id, provider, values, parent_values, &child_deps);
+ *dependencies = _gtk_css_dependencies_union (*dependencies, child_deps);
+
+ return gtk_css_shadow_value_new (hoffset, voffset, radius, spread, shadow->inset, color);
+}
+
static gboolean
gtk_css_value_shadow_equal (const GtkCssValue *shadow1,
const GtkCssValue *shadow2)
{
- /* FIXME */
- return shadow1 == shadow2;
+ return shadow1->inset == shadow2->inset
+ && _gtk_css_value_equal (shadow1->hoffset, shadow2->hoffset)
+ && _gtk_css_value_equal (shadow1->voffset, shadow2->voffset)
+ && _gtk_css_value_equal (shadow1->radius, shadow2->radius)
+ && _gtk_css_value_equal (shadow1->spread, shadow2->spread)
+ && _gtk_css_value_equal (shadow1->color, shadow2->color);
}
static GtkCssValue *
gtk_css_value_shadow_transition (GtkCssValue *start,
GtkCssValue *end,
+ guint property_id,
double progress)
{
- return NULL;
+ if (start->inset != end->inset)
+ return NULL;
+
+ return gtk_css_shadow_value_new (_gtk_css_value_transition (start->hoffset, end->hoffset, property_id, progress),
+ _gtk_css_value_transition (start->voffset, end->voffset, property_id, progress),
+ _gtk_css_value_transition (start->radius, end->radius, property_id, progress),
+ _gtk_css_value_transition (start->spread, end->spread, property_id, progress),
+ start->inset,
+ _gtk_css_value_transition (start->color, end->color, property_id, progress));
}
static void
static const GtkCssValueClass GTK_CSS_VALUE_SHADOW = {
gtk_css_value_shadow_free,
+ gtk_css_value_shadow_compute,
gtk_css_value_shadow_equal,
gtk_css_value_shadow_transition,
gtk_css_value_shadow_print
return retval;
}
+GtkCssValue *
+_gtk_css_shadow_value_new_for_transition (GtkCssValue *target)
+{
+ GdkRGBA transparent = { 0, 0, 0, 0 };
+
+ g_return_val_if_fail (target->class == >K_CSS_VALUE_SHADOW, NULL);
+
+ return gtk_css_shadow_value_new (_gtk_css_number_value_new (0, GTK_CSS_PX),
+ _gtk_css_number_value_new (0, GTK_CSS_PX),
+ _gtk_css_number_value_new (0, GTK_CSS_PX),
+ _gtk_css_number_value_new (0, GTK_CSS_PX),
+ target->inset,
+ _gtk_css_rgba_value_new_from_rgba (&transparent));
+}
+
static gboolean
value_is_done_parsing (GtkCssParser *parser)
{
}
else if (values[COLOR] == NULL)
{
- GtkSymbolicColor *symbolic;
+ values[COLOR] = _gtk_css_color_value_parse (parser);
- if (_gtk_css_parser_try (parser, "currentcolor", TRUE))
- symbolic = gtk_symbolic_color_ref (_gtk_symbolic_color_get_current_color ());
- else
- symbolic = _gtk_css_parser_read_symbolic_color (parser);
- if (symbolic == NULL)
+ if (values[COLOR] == NULL)
goto fail;
-
- values[COLOR] = _gtk_css_value_new_take_symbolic_color (symbolic);
}
else
{
while (values[HOFFSET] == NULL || !value_is_done_parsing (parser));
if (values[COLOR] == NULL)
- values[COLOR] = _gtk_css_value_new_take_symbolic_color (
- gtk_symbolic_color_ref (
- _gtk_symbolic_color_get_current_color ()));
+ values[COLOR] = _gtk_css_color_value_new_current_color ();
return gtk_css_shadow_value_new (values[HOFFSET], values[VOFFSET],
values[RADIUS], values[SPREAD],
return NULL;
}
-GtkCssValue *
-_gtk_css_shadow_value_compute (GtkCssValue *shadow,
- GtkStyleContext *context)
+static const cairo_user_data_key_t shadow_key;
+
+static cairo_t *
+gtk_css_shadow_value_start_drawing (const GtkCssValue *shadow,
+ cairo_t *cr)
{
- GtkCssValue *color;
+ cairo_rectangle_int_t clip_rect;
+ cairo_surface_t *surface;
+ cairo_t *blur_cr;
+ gdouble radius;
+
+ radius = _gtk_css_number_value_get (shadow->radius, 0);
+ if (radius == 0.0)
+ return cr;
+
+ gdk_cairo_get_clip_rectangle (cr, &clip_rect);
+
+ /* Create a larger surface to center the blur. */
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ clip_rect.width + 2 * radius,
+ clip_rect.height + 2 * radius);
+ cairo_surface_set_device_offset (surface, radius - clip_rect.x, radius - clip_rect.y);
+ blur_cr = cairo_create (surface);
+ cairo_set_user_data (blur_cr, &shadow_key, cairo_reference (cr), (cairo_destroy_func_t) cairo_destroy);
+
+ if (cairo_has_current_point (cr))
+ {
+ double x, y;
+
+ cairo_get_current_point (cr, &x, &y);
+ cairo_move_to (blur_cr, x, y);
+ }
+
+ return blur_cr;
+}
+
+static cairo_t *
+gtk_css_shadow_value_finish_drawing (const GtkCssValue *shadow,
+ cairo_t *cr)
+{
+ gdouble radius;
+ cairo_t *original_cr;
+ cairo_surface_t *surface;
+
+ radius = _gtk_css_number_value_get (shadow->radius, 0);
+ if (radius == 0.0)
+ return cr;
- color = _gtk_css_rgba_value_compute_from_symbolic (shadow->color,
- _gtk_css_value_new_take_symbolic_color (
- gtk_symbolic_color_ref (
- _gtk_symbolic_color_get_current_color ())),
- context,
- FALSE);
-
- return gtk_css_shadow_value_new (_gtk_css_number_value_compute (shadow->hoffset, context),
- _gtk_css_number_value_compute (shadow->voffset, context),
- _gtk_css_number_value_compute (shadow->radius, context),
- _gtk_css_number_value_compute (shadow->spread, context),
- shadow->inset,
- color);
+ surface = cairo_get_target (cr);
+ original_cr = cairo_get_user_data (cr, &shadow_key);
+
+ /* Blur the surface. */
+ _gtk_cairo_blur_surface (surface, radius);
+
+ cairo_set_source_surface (original_cr, surface, 0, 0);
+ cairo_paint (original_cr);
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
+ return original_cr;
}
void
cairo_rel_move_to (cr,
_gtk_css_number_value_get (shadow->hoffset, 0),
_gtk_css_number_value_get (shadow->voffset, 0));
+
+ cr = gtk_css_shadow_value_start_drawing (shadow, cr);
+
gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (shadow->color));
_gtk_pango_fill_layout (cr, layout);
+ cr = gtk_css_shadow_value_finish_drawing (shadow, cr);
+
cairo_rel_move_to (cr,
- _gtk_css_number_value_get (shadow->hoffset, 0),
- _gtk_css_number_value_get (shadow->voffset, 0));
cairo_save (cr);
pattern = cairo_pattern_reference (cairo_get_source (cr));
+
+ cr = gtk_css_shadow_value_start_drawing (shadow, cr);
+
gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (shadow->color));
cairo_translate (cr,
_gtk_css_number_value_get (shadow->voffset, 0));
cairo_mask (cr, pattern);
+ cr = gtk_css_shadow_value_finish_drawing (shadow, cr);
+
cairo_restore (cr);
cairo_pattern_destroy (pattern);
}
cairo_save (cr);
+ cr = gtk_css_shadow_value_start_drawing (shadow, cr);
+
cairo_translate (cr,
_gtk_css_number_value_get (shadow->hoffset, 0),
_gtk_css_number_value_get (shadow->voffset, 0));
radius, progress,
_gtk_css_rgba_value_get_rgba (shadow->color));
+ cr = gtk_css_shadow_value_finish_drawing (shadow, cr);
+
cairo_restore (cr);
}
cairo_t *cr,
const GtkRoundedBox *padding_box)
{
- GtkRoundedBox box;
- double spread;
+ GtkRoundedBox box, clip_box;
+ double spread, radius;
g_return_if_fail (shadow->class == >K_CSS_VALUE_SHADOW);
cairo_save (cr);
- cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
_gtk_rounded_box_path (padding_box, cr);
cairo_clip (cr);
spread = _gtk_css_number_value_get (shadow->spread, 0);
_gtk_rounded_box_shrink (&box, spread, spread, spread, spread);
+ clip_box = *padding_box;
+ radius = _gtk_css_number_value_get (shadow->radius, 0);
+ _gtk_rounded_box_shrink (&clip_box, -radius, -radius, -radius, -radius);
+
+ cr = gtk_css_shadow_value_start_drawing (shadow, cr);
+
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
_gtk_rounded_box_path (&box, cr);
- _gtk_rounded_box_clip_path (padding_box, cr);
+ _gtk_rounded_box_clip_path (&clip_box, cr);
gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (shadow->color));
cairo_fill (cr);
+ cr = gtk_css_shadow_value_finish_drawing (shadow, cr);
+
cairo_restore (cr);
}