[gtk+/wip/css: 36/37] css: Make linear-gradient() use premultiplied transitions



commit f6fcc8333922fa6d3f3eb73609ddfacc87f2d2d9
Author: Benjamin Otte <otte redhat com>
Date:   Mon Jan 23 11:59:47 2012 +0100

    css: Make linear-gradient() use premultiplied transitions
    
    The CSS spec wants CSS gradients to transition in premultiplied space.
    These tricks ensure that, though the real fix for that would be to add
    features to cairo that make sure gradients work that way by default.

 gtk/gtkcssimagelinear.c        |   58 +++++++++++++++++++++++++++++++++------
 gtk/gtkcssimagelinearprivate.h |    1 +
 2 files changed, 50 insertions(+), 9 deletions(-)
---
diff --git a/gtk/gtkcssimagelinear.c b/gtk/gtkcssimagelinear.c
index 130f9d9..85c6bf9 100644
--- a/gtk/gtkcssimagelinear.c
+++ b/gtk/gtkcssimagelinear.c
@@ -130,7 +130,7 @@ gtk_css_image_linear_draw (GtkCssImage        *image,
                            double              height)
 {
   GtkCssImageLinear *linear = GTK_CSS_IMAGE_LINEAR (image);
-  cairo_pattern_t *pattern;
+  cairo_pattern_t *pattern, *mask;
   double x, y; /* coordinates of start point */
   double length; /* distance in pixels for 100% */
   double start, end; /* position of first/last point on gradient line - with gradient line being [0, 1] */
@@ -173,6 +173,18 @@ gtk_css_image_linear_draw (GtkCssImage        *image,
   else
     cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
 
+  if (linear->needs_mask)
+    {
+      mask = cairo_pattern_create_linear (x * (start - 0.5), y * (start - 0.5),
+                                             x * (end - 0.5),   y * (end - 0.5));
+      if (linear->repeating)
+        cairo_pattern_set_extend (mask, CAIRO_EXTEND_REPEAT);
+      else
+        cairo_pattern_set_extend (mask, CAIRO_EXTEND_PAD);
+    }
+  else
+    mask = NULL;
+
   offset = start;
   last = -1;
   for (i = 0; i < linear->stops->len; i++)
@@ -204,12 +216,16 @@ gtk_css_image_linear_draw (GtkCssImage        *image,
 
           offset += step;
 
-          cairo_pattern_add_color_stop_rgba (pattern,
-                                             (offset - start) / (end - start),
-                                             stop->color.rgba.red,
-                                             stop->color.rgba.green,
-                                             stop->color.rgba.blue,
-                                             stop->color.rgba.alpha);
+          cairo_pattern_add_color_stop_rgb (pattern,
+                                            (offset - start) / (end - start),
+                                            stop->color.rgba.red * stop->color.rgba.alpha,
+                                            stop->color.rgba.green * stop->color.rgba.alpha,
+                                            stop->color.rgba.blue * stop->color.rgba.alpha);
+          if (mask)
+            cairo_pattern_add_color_stop_rgba (mask,
+                                               (offset - start) / (end - start),
+                                               1, 1, 1,
+                                               stop->color.rgba.alpha);
         }
 
       offset = pos;
@@ -218,8 +234,31 @@ gtk_css_image_linear_draw (GtkCssImage        *image,
 
   cairo_rectangle (cr, 0, 0, width, height);
   cairo_translate (cr, width / 2, height / 2);
-  cairo_set_source (cr, pattern);
-  cairo_fill (cr);
+
+  if (mask)
+    {
+      cairo_clip (cr);
+
+      /* This magic achieves a premultiplied gradient
+       * transition */
+      cairo_push_group (cr);
+
+      cairo_set_source (cr, mask);
+      cairo_paint (cr);
+      cairo_set_operator (cr, CAIRO_OPERATOR_IN);
+      cairo_set_source (cr, pattern);
+      cairo_paint (cr);
+
+      cairo_pop_group_to_source (cr);
+      cairo_paint (cr);
+
+      cairo_pattern_destroy (mask);
+    }
+  else
+    {
+      cairo_set_source (cr, pattern);
+      cairo_fill (cr);
+    }
 
   cairo_pattern_destroy (pattern);
 }
@@ -453,6 +492,7 @@ gtk_css_image_linear_compute (GtkCssImage     *image,
         }
       
       _gtk_css_number_compute (&scopy->offset, &stop->offset, context);
+      copy->needs_mask |= scopy->color.rgba.alpha < 1;
     }
 
   return GTK_CSS_IMAGE (copy);
diff --git a/gtk/gtkcssimagelinearprivate.h b/gtk/gtkcssimagelinearprivate.h
index f664c5b..9b9711b 100644
--- a/gtk/gtkcssimagelinearprivate.h
+++ b/gtk/gtkcssimagelinearprivate.h
@@ -52,6 +52,7 @@ struct _GtkCssImageLinear
   GArray *stops;
   guint is_computed :1;
   guint repeating :1;
+  guint needs_mask :1;
 };
 
 struct _GtkCssImageLinearClass



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