From 3b436eec6d9b0c7aa046ff4b2b4c3a9f99b86574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Sun, 6 Nov 2011 19:33:05 +0100 Subject: [PATCH] css: start background-repeat By default, a background image is stretched. Instead, it is worth to have a tiled background. This patch allows background surfaces to be repeated or not, and should be compatible with future extensions and CSS. https://bugzilla.gnome.org/show_bug.cgi?id=663522 --- gtk/gtkcssprovider.c | 10 +++++++ gtk/gtkcsstypes.c | 2 ++ gtk/gtkcsstypesprivate.h | 17 ++++++++++++ gtk/gtkstylecontext.h | 1 - gtk/gtkstyleproperty.c | 56 ++++++++++++++++++++++++++++++++++++++++ gtk/gtkthemingengine.c | 31 ++++++++++++++++++++-- 6 files changed, 114 insertions(+), 3 deletions(-) diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c index 12457668e3..555a4b523b 100644 --- a/gtk/gtkcssprovider.c +++ b/gtk/gtkcssprovider.c @@ -840,6 +840,16 @@ * * * + * background-repeat + * [repeat|no-repeat] + * internal + * background-repeat: no-repeat; + * If not specified, the style doesn't respect the CSS3 + * specification, since the background will be + * stretched to fill the area. + * + * + * * border-top-width * integer * #gint diff --git a/gtk/gtkcsstypes.c b/gtk/gtkcsstypes.c index e84bd2c477..73f2d16ee8 100644 --- a/gtk/gtkcsstypes.c +++ b/gtk/gtkcsstypes.c @@ -31,6 +31,8 @@ type_name ## _copy (const TypeName *foo) \ \ G_DEFINE_BOXED_TYPE (TypeName, type_name, type_name ## _copy, g_free) +DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBackgroundRepeat, _gtk_css_background_repeat) + DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBorderCornerRadius, _gtk_css_border_corner_radius) DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBorderRadius, _gtk_css_border_radius) DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBorderImageRepeat, _gtk_css_border_image_repeat) diff --git a/gtk/gtkcsstypesprivate.h b/gtk/gtkcsstypesprivate.h index 0ee049a328..4dc93fa735 100644 --- a/gtk/gtkcsstypesprivate.h +++ b/gtk/gtkcsstypesprivate.h @@ -24,6 +24,12 @@ G_BEGIN_DECLS +typedef enum { + GTK_CSS_BACKGROUND_REPEAT_STYLE_NONE, + GTK_CSS_BACKGROUND_REPEAT_STYLE_REPEAT, + GTK_CSS_BACKGROUND_REPEAT_STYLE_NO_REPEAT, +} GtkCssBackgroundRepeatStyle; + typedef enum { GTK_CSS_REPEAT_STYLE_NONE, GTK_CSS_REPEAT_STYLE_REPEAT, @@ -31,10 +37,17 @@ typedef enum { GTK_CSS_REPEAT_STYLE_SPACE } GtkCssBorderRepeatStyle; +typedef struct _GtkCssBackgroundRepeat GtkCssBackgroundRepeat; + typedef struct _GtkCssBorderCornerRadius GtkCssBorderCornerRadius; typedef struct _GtkCssBorderRadius GtkCssBorderRadius; typedef struct _GtkCssBorderImageRepeat GtkCssBorderImageRepeat; +struct _GtkCssBackgroundRepeat { + /* FIXME: will have vrepeat and hrepeat instead */ + GtkCssBackgroundRepeatStyle repeat; +}; + struct _GtkCssBorderCornerRadius { double horizontal; double vertical; @@ -52,10 +65,14 @@ struct _GtkCssBorderImageRepeat { GtkCssBorderRepeatStyle hrepeat; }; +#define GTK_TYPE_CSS_BACKGROUND_REPEAT _gtk_css_background_repeat_get_type () + #define GTK_TYPE_CSS_BORDER_CORNER_RADIUS _gtk_css_border_corner_radius_get_type () #define GTK_TYPE_CSS_BORDER_RADIUS _gtk_css_border_radius_get_type () #define GTK_TYPE_CSS_BORDER_IMAGE_REPEAT _gtk_css_border_image_repeat_get_type () +GType _gtk_css_background_repeat_get_type (void); + GType _gtk_css_border_corner_radius_get_type (void); GType _gtk_css_border_radius_get_type (void); GType _gtk_css_border_image_repeat_get_type (void); diff --git a/gtk/gtkstylecontext.h b/gtk/gtkstylecontext.h index b5af48b60a..634c31adfd 100644 --- a/gtk/gtkstylecontext.h +++ b/gtk/gtkstylecontext.h @@ -148,7 +148,6 @@ struct _GtkStyleContextClass */ #define GTK_STYLE_PROPERTY_BACKGROUND_IMAGE "background-image" - /* Predefined set of CSS classes */ /** diff --git a/gtk/gtkstyleproperty.c b/gtk/gtkstyleproperty.c index 6997293629..8913d92560 100644 --- a/gtk/gtkstyleproperty.c +++ b/gtk/gtkstyleproperty.c @@ -1126,6 +1126,53 @@ shadow_value_print (const GValue *value, _gtk_shadow_print (shadow, string); } +static gboolean +background_repeat_value_parse (GtkCssParser *parser, + GFile *file, + GValue *value) +{ + GtkCssBackgroundRepeat repeat; + GtkCssBackgroundRepeatStyle style; + + if (_gtk_css_parser_try (parser, "repeat", TRUE)) + style = GTK_CSS_BACKGROUND_REPEAT_STYLE_REPEAT; + else if (_gtk_css_parser_try (parser, "no-repeat", TRUE)) + style = GTK_CSS_BACKGROUND_REPEAT_STYLE_NO_REPEAT; + else + style = GTK_CSS_BACKGROUND_REPEAT_STYLE_NONE; + + repeat.repeat = style; + + g_value_set_boxed (value, &repeat); + + return TRUE; +} + +static const gchar * +background_repeat_style_to_string (GtkCssBackgroundRepeatStyle repeat) +{ + switch (repeat) + { + case GTK_CSS_BACKGROUND_REPEAT_STYLE_REPEAT: + return "repeat"; + case GTK_CSS_BACKGROUND_REPEAT_STYLE_NO_REPEAT: + return "no-repeat"; + default: + return NULL; + } +} + +static void +background_repeat_value_print (const GValue *value, + GString *string) +{ + GtkCssBackgroundRepeat *repeat; + + repeat = g_value_get_boxed (value); + + g_string_append (string, background_repeat_style_to_string (repeat->repeat)); +} + static gboolean border_image_repeat_value_parse (GtkCssParser *parser, GFile *file, @@ -2246,6 +2293,9 @@ css_string_funcs_init (void) register_conversion_function (G_TYPE_FLAGS, flags_value_parse, flags_value_print); + register_conversion_function (GTK_TYPE_CSS_BACKGROUND_REPEAT, + background_repeat_value_parse, + background_repeat_value_print); } gboolean @@ -2912,6 +2962,12 @@ gtk_style_property_init (void) "Background Image", "Background Image", CAIRO_GOBJECT_TYPE_PATTERN, 0)); + gtk_style_properties_register_property (NULL, + g_param_spec_boxed ("background-repeat", + "Background repeat", + "Background repeat", + GTK_TYPE_CSS_BACKGROUND_REPEAT, 0)); + gtk_style_properties_register_property (NULL, g_param_spec_boxed ("border-image-source", "Border image source", diff --git a/gtk/gtkthemingengine.c b/gtk/gtkthemingengine.c index d917a0c65c..8d6da01018 100644 --- a/gtk/gtkthemingengine.c +++ b/gtk/gtkthemingengine.c @@ -1381,6 +1381,7 @@ render_background_internal (GtkThemingEngine *engine, { GdkRGBA bg_color; cairo_pattern_t *pattern; + GtkCssBackgroundRepeat *repeat; GtkStateFlags flags; gboolean running; gdouble progress; @@ -1394,6 +1395,7 @@ render_background_internal (GtkThemingEngine *engine, gtk_theming_engine_get (engine, flags, "background-image", &pattern, + "background-repeat", &repeat, "box-shadow", &box_shadow, NULL); @@ -1602,9 +1604,31 @@ render_background_internal (GtkThemingEngine *engine, if (pattern) { - cairo_scale (cr, width, height); + cairo_surface_t *surface; + int scale_width, scale_height; + + if (cairo_pattern_get_surface (pattern, &surface) != CAIRO_STATUS_SUCCESS) + surface = NULL; + + if (surface && repeat && + repeat->repeat != GTK_CSS_BACKGROUND_REPEAT_STYLE_NONE) + { + scale_width = cairo_image_surface_get_width (surface); + scale_height = cairo_image_surface_get_height (surface); + if (repeat->repeat == GTK_CSS_BACKGROUND_REPEAT_STYLE_REPEAT) + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + else if (repeat->repeat == GTK_CSS_BACKGROUND_REPEAT_STYLE_NO_REPEAT) + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE); + } + else + { + scale_width = width; + scale_height = height; + } + + cairo_scale (cr, scale_width, scale_height); cairo_set_source (cr, pattern); - cairo_scale (cr, 1.0 / width, 1.0 / height); + cairo_scale (cr, 1.0 / scale_width, 1.0 / scale_height); } else gdk_cairo_set_source_rgba (cr, &bg_color); @@ -1614,6 +1638,9 @@ render_background_internal (GtkThemingEngine *engine, if (pattern) cairo_pattern_destroy (pattern); + if (repeat) + g_free (repeat); + if (box_shadow != NULL) { _gtk_box_shadow_render (box_shadow, cr, &border_box);