diff options
-rw-r--r-- | gtk/Makefile.am | 2 | ||||
-rw-r--r-- | gtk/gtkcssimage.c | 4 | ||||
-rw-r--r-- | gtk/gtkcssimagecrossfade.c | 269 | ||||
-rw-r--r-- | gtk/gtkcssimagecrossfadeprivate.h | 59 |
4 files changed, 333 insertions, 1 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 54faaa1a06..5559b074ec 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -428,6 +428,7 @@ gtk_private_h_sources = \ gtkcsscustompropertyprivate.h \ gtkcsseasevalueprivate.h \ gtkcssenumvalueprivate.h \ + gtkcssimagecrossfadeprivate.h \ gtkcssimagegradientprivate.h \ gtkcssimagelinearprivate.h \ gtkcssimageprivate.h \ @@ -635,6 +636,7 @@ gtk_base_c_sources = \ gtkcsseasevalue.c \ gtkcssenumvalue.c \ gtkcssimage.c \ + gtkcssimagecrossfade.c \ gtkcssimagegradient.c \ gtkcssimagelinear.c \ gtkcssimageurl.c \ diff --git a/gtk/gtkcssimage.c b/gtk/gtkcssimage.c index a89402e2a7..66ceffe771 100644 --- a/gtk/gtkcssimage.c +++ b/gtk/gtkcssimage.c @@ -22,6 +22,7 @@ #include "gtkcssimageprivate.h" /* for the types only */ +#include "gtk/gtkcssimagecrossfadeprivate.h" #include "gtk/gtkcssimagegradientprivate.h" #include "gtk/gtkcssimagelinearprivate.h" #include "gtk/gtkcssimageurlprivate.h" @@ -324,7 +325,8 @@ gtk_css_image_get_parser_type (GtkCssParser *parser) { "-gtk-gradient", _gtk_css_image_gradient_get_type }, { "-gtk-win32-theme-part", _gtk_css_image_win32_get_type }, { "linear-gradient", _gtk_css_image_linear_get_type }, - { "repeating-linear-gradient", _gtk_css_image_linear_get_type } + { "repeating-linear-gradient", _gtk_css_image_linear_get_type }, + { "cross-fade", _gtk_css_image_cross_fade_get_type } }; guint i; diff --git a/gtk/gtkcssimagecrossfade.c b/gtk/gtkcssimagecrossfade.c new file mode 100644 index 0000000000..43d0b6d56f --- /dev/null +++ b/gtk/gtkcssimagecrossfade.c @@ -0,0 +1,269 @@ +/* + * Copyright © 2012 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 "gtkcssimagecrossfadeprivate.h" + +#include "gtkcssnumbervalueprivate.h" + +G_DEFINE_TYPE (GtkCssImageCrossFade, _gtk_css_image_cross_fade, GTK_TYPE_CSS_IMAGE) + +static int +gtk_css_image_cross_fade_get_width (GtkCssImage *image) +{ + GtkCssImageCrossFade *cross_fade = GTK_CSS_IMAGE_CROSS_FADE (image); + int start_width, end_width; + + if (cross_fade->start) + { + start_width = _gtk_css_image_get_width (cross_fade->start); + /* no intrinsic width, what now? */ + if (start_width == 0) + return 0; + } + else + start_width = 0; + + if (cross_fade->end) + { + end_width = _gtk_css_image_get_width (cross_fade->end); + /* no intrinsic width, what now? */ + if (end_width == 0) + return 0; + } + else + end_width = 0; + + return start_width + (end_width - start_width) * cross_fade->progress; +} + +static int +gtk_css_image_cross_fade_get_height (GtkCssImage *image) +{ + GtkCssImageCrossFade *cross_fade = GTK_CSS_IMAGE_CROSS_FADE (image); + int start_height, end_height; + + if (cross_fade->start) + { + start_height = _gtk_css_image_get_height (cross_fade->start); + /* no intrinsic height, what now? */ + if (start_height == 0) + return 0; + } + else + start_height = 0; + + if (cross_fade->end) + { + end_height = _gtk_css_image_get_height (cross_fade->end); + /* no intrinsic height, what now? */ + if (end_height == 0) + return 0; + } + else + end_height = 0; + + return start_height + (end_height - start_height) * cross_fade->progress; +} + +static void +gtk_css_image_cross_fade_draw (GtkCssImage *image, + cairo_t *cr, + double width, + double height) +{ + GtkCssImageCrossFade *cross_fade = GTK_CSS_IMAGE_CROSS_FADE (image); + + if (cross_fade->progress <= 0.0) + { + if (cross_fade->start) + _gtk_css_image_draw (cross_fade->start, cr, width, height); + } + else if (cross_fade->progress >= 1.0) + { + if (cross_fade->end) + _gtk_css_image_draw (cross_fade->end, cr, width, height); + } + else + { + cairo_surface_t *surface; + + if (cross_fade->start && cross_fade->end) + { + /* to reduce the group size */ + cairo_rectangle (cr, 0, 0, width, height); + cairo_clip (cr); + + cairo_push_group (cr); + + _gtk_css_image_draw (cross_fade->start, cr, width, height); + + surface = _gtk_css_image_get_surface (cross_fade->end, + cairo_get_target (cr), + width, height); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint_with_alpha (cr, cross_fade->progress); + cairo_surface_destroy (surface); + + cairo_pop_group_to_source (cr); + cairo_paint (cr); + } + else if (cross_fade->start || cross_fade->end) + { + surface = _gtk_css_image_get_surface (cross_fade->start ? cross_fade->start : cross_fade->end, + cairo_get_target (cr), + width, height); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint_with_alpha (cr, cross_fade->start ? 1.0 - cross_fade->progress : cross_fade->progress); + cairo_surface_destroy (surface); + } + } +} + +static gboolean +gtk_css_image_cross_fade_parse (GtkCssImage *image, + GtkCssParser *parser, + GFile *base) +{ + GtkCssImageCrossFade *cross_fade = GTK_CSS_IMAGE_CROSS_FADE (image); + GtkCssValue *number; + + if (!_gtk_css_parser_try (parser, "cross-fade(", TRUE)) + { + _gtk_css_parser_error (parser, "Expected 'cross-fade('"); + return FALSE; + } + + cross_fade->start = _gtk_css_image_new_parse (parser, base); + if (cross_fade->start == NULL) + return FALSE; + + if (!_gtk_css_parser_try (parser, ",", TRUE)) + { + _gtk_css_parser_error (parser, "Missing comma after first image"); + return FALSE; + } + + cross_fade->end = _gtk_css_image_new_parse (parser, base); + if (cross_fade->end == NULL) + return FALSE; + + if (!_gtk_css_parser_try (parser, ",", TRUE)) + { + _gtk_css_parser_error (parser, "Missing comma after second image"); + return FALSE; + } + + if (!_gtk_css_parser_try (parser, ")", TRUE)) + { + _gtk_css_parser_error (parser, "Missing closing bracket"); + return FALSE; + } + + number = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_PERCENT | GTK_CSS_POSITIVE_ONLY); + if (number == NULL) + return FALSE; + cross_fade->progress = _gtk_css_number_value_get (number, 1); + _gtk_css_value_unref (number); + + if (cross_fade->progress > 100) + { + _gtk_css_parser_error (parser, "Percentages ovre 100%% are not allowed"); + return FALSE; + } + cross_fade->progress /= 100.0; + + return TRUE; +} + +static void +gtk_css_image_cross_fade_print (GtkCssImage *image, + GString *string) +{ + GtkCssImageCrossFade *cross_fade = GTK_CSS_IMAGE_CROSS_FADE (image); + + g_string_append (string, "cross_fade("); + if (cross_fade->start) + _gtk_css_image_print (cross_fade->start, string); + else + g_string_append (string, "none"); + g_string_append (string, ","); + if (cross_fade->end) + _gtk_css_image_print (cross_fade->end, string); + else + g_string_append (string, "none"); + g_string_append (string, ","); + g_string_append_printf (string, "%g%%", cross_fade->progress * 100.0); + g_string_append (string, ")"); +} + +static void +gtk_css_image_cross_fade_dispose (GObject *object) +{ + GtkCssImageCrossFade *cross_fade = GTK_CSS_IMAGE_CROSS_FADE (object); + + g_clear_object (&cross_fade->start); + g_clear_object (&cross_fade->end); + + G_OBJECT_CLASS (_gtk_css_image_cross_fade_parent_class)->dispose (object); +} + +static void +_gtk_css_image_cross_fade_class_init (GtkCssImageCrossFadeClass *klass) +{ + GtkCssImageClass *image_class = GTK_CSS_IMAGE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + image_class->get_width = gtk_css_image_cross_fade_get_width; + image_class->get_height = gtk_css_image_cross_fade_get_height; + image_class->draw = gtk_css_image_cross_fade_draw; + image_class->parse = gtk_css_image_cross_fade_parse; + image_class->print = gtk_css_image_cross_fade_print; + + object_class->dispose = gtk_css_image_cross_fade_dispose; +} + +static void +_gtk_css_image_cross_fade_init (GtkCssImageCrossFade *image_cross_fade) +{ +} + +GtkCssImage * +_gtk_css_image_cross_fade_new (GtkCssImage *start, + GtkCssImage *end, + double progress) +{ + GtkCssImageCrossFade *cross_fade; + + g_return_val_if_fail (start == NULL || GTK_IS_CSS_IMAGE (start), NULL); + g_return_val_if_fail (end == NULL || GTK_IS_CSS_IMAGE (end), NULL); + + cross_fade = g_object_new (GTK_TYPE_CSS_IMAGE_CROSS_FADE, NULL); + if (start) + cross_fade->start = g_object_ref (start); + if (end) + cross_fade->end = g_object_ref (end); + cross_fade->progress = progress; + + return GTK_CSS_IMAGE (cross_fade); +} + diff --git a/gtk/gtkcssimagecrossfadeprivate.h b/gtk/gtkcssimagecrossfadeprivate.h new file mode 100644 index 0000000000..54929317e4 --- /dev/null +++ b/gtk/gtkcssimagecrossfadeprivate.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2012 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> + */ + +#ifndef __GTK_CSS_IMAGE_CROSS_FADE_PRIVATE_H__ +#define __GTK_CSS_IMAGE_CROSS_FADE_PRIVATE_H__ + +#include "gtk/gtkcssimageprivate.h" + +G_BEGIN_DECLS + +#define GTK_TYPE_CSS_IMAGE_CROSS_FADE (_gtk_css_image_cross_fade_get_type ()) +#define GTK_CSS_IMAGE_CROSS_FADE(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_IMAGE_CROSS_FADE, GtkCssImageCrossFade)) +#define GTK_CSS_IMAGE_CROSS_FADE_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_IMAGE_CROSS_FADE, GtkCssImageCrossFadeClass)) +#define GTK_IS_CSS_IMAGE_CROSS_FADE(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_IMAGE_CROSS_FADE)) +#define GTK_IS_CSS_IMAGE_CROSS_FADE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_IMAGE_CROSS_FADE)) +#define GTK_CSS_IMAGE_CROSS_FADE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_IMAGE_CROSS_FADE, GtkCssImageCrossFadeClass)) + +typedef struct _GtkCssImageCrossFade GtkCssImageCrossFade; +typedef struct _GtkCssImageCrossFadeClass GtkCssImageCrossFadeClass; + +struct _GtkCssImageCrossFade +{ + GtkCssImage parent; + + GtkCssImage *start; + GtkCssImage *end; + double progress; +}; + +struct _GtkCssImageCrossFadeClass +{ + GtkCssImageClass parent_class; +}; + +GType _gtk_css_image_cross_fade_get_type (void) G_GNUC_CONST; + +GtkCssImage * _gtk_css_image_cross_fade_new (GtkCssImage *start, + GtkCssImage *end, + double progress); + +G_END_DECLS + +#endif /* __GTK_CSS_IMAGE_CROSS_FADE_PRIVATE_H__ */ |