diff options
author | Benjamin Otte <otte@redhat.com> | 2012-01-05 16:33:39 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2012-01-09 18:37:58 +0100 |
commit | bbf5fe179d88bdd16bd2addcbf8509e9a210ac05 (patch) | |
tree | f90fd66cce0884e2683ee798dbea17987a919aeb /gtk/gtkthemingbackground.c | |
parent | af8c7ebecd21220a2f6c518f2c1bebf47f28f79c (diff) | |
download | gtk+-bbf5fe179d88bdd16bd2addcbf8509e9a210ac05.tar.gz |
background: Implement all options of background-repeat
Diffstat (limited to 'gtk/gtkthemingbackground.c')
-rw-r--r-- | gtk/gtkthemingbackground.c | 119 |
1 files changed, 114 insertions, 5 deletions
diff --git a/gtk/gtkthemingbackground.c b/gtk/gtkthemingbackground.c index b786db67c5..a022c9d0eb 100644 --- a/gtk/gtkthemingbackground.c +++ b/gtk/gtkthemingbackground.c @@ -21,12 +21,21 @@ * Boston, MA 02111-1307, USA. */ +#include "config.h" + #include "gtkcsstypesprivate.h" #include "gtkthemingbackgroundprivate.h" #include "gtkthemingengineprivate.h" +#include <math.h> + #include <gdk/gdk.h> +/* this is in case round() is not provided by the compiler, + * such as in the case of C89 compilers, like MSVC + */ +#include "fallback-c89.c" + static void _gtk_theming_background_apply_window_background (GtkThemingBackground *bg, cairo_t *cr) @@ -116,21 +125,121 @@ _gtk_theming_background_paint (GtkThemingBackground *bg, if (bg->image) { - GtkCssBackgroundRepeat repeat; + GtkCssBackgroundRepeat hrepeat, vrepeat; double image_width, image_height; + double width, height; gtk_theming_engine_get (bg->engine, bg->flags, - "background-repeat", &repeat, + "background-repeat", &hrepeat, NULL); + vrepeat = GTK_CSS_BACKGROUND_VERTICAL (hrepeat); + hrepeat = GTK_CSS_BACKGROUND_HORIZONTAL (hrepeat); + width = bg->image_rect.width; + height = bg->image_rect.height; _gtk_css_image_get_concrete_size (bg->image, 0, 0, /* XXX: needs background-size support */ - bg->image_rect.width, bg->image_rect.height, + width, height, &image_width, &image_height); + /* optimization */ + if (image_width == width) + hrepeat = GTK_CSS_BACKGROUND_NO_REPEAT; + if (image_height == height) + vrepeat = GTK_CSS_BACKGROUND_NO_REPEAT; + cairo_translate (cr, bg->image_rect.x, bg->image_rect.y); - /* XXX: repeat flags */ - _gtk_css_image_draw (bg->image, cr, image_width, image_height); + + if (hrepeat == GTK_CSS_BACKGROUND_NO_REPEAT && vrepeat == GTK_CSS_BACKGROUND_NO_REPEAT) + { + /* shortcut for normal case */ + _gtk_css_image_draw (bg->image, cr, image_width, image_height); + } + else + { + int surface_width, surface_height; + cairo_surface_t *surface; + cairo_t *cr2; + + /* If ‘background-repeat’ is ‘round’ for one (or both) dimensions, + * there is a second step. The UA must scale the image in that + * dimension (or both dimensions) so that it fits a whole number of + * times in the background positioning area. In the case of the width + * (height is analogous): + * + * If X ≠ 0 is the width of the image after step one and W is the width + * of the background positioning area, then the rounded width + * X' = W / round(W / X) where round() is a function that returns the + * nearest natural number (integer greater than zero). + * + * If ‘background-repeat’ is ‘round’ for one dimension only and if + * ‘background-size’ is ‘auto’ for the other dimension, then there is + * a third step: that other dimension is scaled so that the original + * aspect ratio is restored. + */ + if (hrepeat == GTK_CSS_BACKGROUND_ROUND) + { + double n = round (width / image_width); + + n = MAX (1, n); + + if (vrepeat != GTK_CSS_BACKGROUND_ROUND + /* && vsize == auto (it is by default) */) + image_height *= width / (image_width * n); + image_width = width / n; + } + if (vrepeat == GTK_CSS_BACKGROUND_ROUND) + { + double n = round (height / image_height); + + n = MAX (1, n); + + if (hrepeat != GTK_CSS_BACKGROUND_ROUND + /* && hsize == auto (it is by default) */) + image_width *= height / (image_height * n); + image_height = height / n; + } + + /* if hrepeat or vrepeat is 'space', we create a somewhat larger surface + * to store the extra space. */ + if (hrepeat == GTK_CSS_BACKGROUND_SPACE) + { + double n = floor (width / image_width); + surface_width = n ? round (width / n) : 0; + } + else + surface_width = round (image_width); + + if (vrepeat == GTK_CSS_BACKGROUND_SPACE) + { + double n = floor (height / image_height); + surface_height = n ? round (height / n) : 0; + } + else + surface_height = round (image_height); + + surface = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + surface_width, surface_height); + cr2 = cairo_create (surface); + cairo_translate (cr2, + 0.5 * (surface_width - image_width), + 0.5 * (surface_height - image_height)); + _gtk_css_image_draw (bg->image, cr2, image_width, image_height); + cairo_destroy (cr2); + + cairo_set_source_surface (cr, surface, + /* background-position goes here */ + 0, 0); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT); + cairo_surface_destroy (surface); + + cairo_rectangle (cr, + 0, 0, + hrepeat == GTK_CSS_BACKGROUND_NO_REPEAT ? image_width : width, + vrepeat == GTK_CSS_BACKGROUND_NO_REPEAT ? image_height : height); + cairo_fill (cr); + } } cairo_restore (cr); |