[gtk+] background: Implement all options of background-repeat



commit bbf5fe179d88bdd16bd2addcbf8509e9a210ac05
Author: Benjamin Otte <otte redhat com>
Date:   Thu Jan 5 16:33:39 2012 +0100

    background: Implement all options of background-repeat

 gtk/gtkthemingbackground.c |  119 ++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 114 insertions(+), 5 deletions(-)
---
diff --git a/gtk/gtkthemingbackground.c b/gtk/gtkthemingbackground.c
index b786db6..a022c9d 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);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]