[gtk+/wip/otte/rendernode: 72/100] gsk: Implement linear gradient render nodes



commit 51a617420fd09ccf3b50277e7275ecf56883badc
Author: Benjamin Otte <otte redhat com>
Date:   Thu Dec 15 05:42:31 2016 +0100

    gsk: Implement linear gradient render nodes

 docs/reference/gsk/gsk4-sections.txt   |    2 +
 gsk/gskenums.h                         |    5 +
 gsk/gskrendernode.h                    |   20 ++++
 gsk/gskrendernodeimpl.c                |  156 ++++++++++++++++++++++++++++++++
 gtk/gtkcssimagelinear.c                |   63 ++++++++------
 gtk/inspector/gtktreemodelrendernode.c |    2 +
 6 files changed, 222 insertions(+), 26 deletions(-)
---
diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt
index c044864..59e1a39 100644
--- a/docs/reference/gsk/gsk4-sections.txt
+++ b/docs/reference/gsk/gsk4-sections.txt
@@ -33,6 +33,8 @@ GskScalingFilter
 gsk_render_node_set_scaling_filters
 gsk_render_node_set_name
 gsk_color_node_new
+gsk_linear_gradient_node_new
+gsk_repeating_linear_gradient_node_new
 gsk_texture_node_new
 gsk_cairo_node_new
 gsk_cairo_node_get_draw_context
diff --git a/gsk/gskenums.h b/gsk/gskenums.h
index d647495..4e0e0bf 100644
--- a/gsk/gskenums.h
+++ b/gsk/gskenums.h
@@ -28,6 +28,9 @@
  * @GSK_CONTAINER_NODE: A node containing a stack of children
  * @GSK_CAIRO_NODE: A node drawing a #cairo_surface_t
  * @GSK_COLOR_NODE: A node drawing a single color rectangle
+ * @GSK_LINEAR_GRADIENT_NODE: A node drawing a linear gradient
+ * @GSK_REPEATING_LINEAR_GRADIENT_NODE: A node drawing a repeating
+ *     linear gradient
  * @GSK_TEXTURE_NODE: A node drawing a #GskTexture
  * @GSK_TRANSFORM_NODE: A node that renders its child after applying a
  *     matrix transform
@@ -45,6 +48,8 @@ typedef enum {
   GSK_CONTAINER_NODE,
   GSK_CAIRO_NODE,
   GSK_COLOR_NODE,
+  GSK_LINEAR_GRADIENT_NODE,
+  GSK_REPEATING_LINEAR_GRADIENT_NODE,
   GSK_TEXTURE_NODE,
   GSK_TRANSFORM_NODE,
   GSK_OPACITY_NODE,
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index 5d92c73..7562fb9 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -33,6 +33,13 @@ G_BEGIN_DECLS
 #define GSK_IS_RENDER_NODE(obj) ((obj) != NULL)
 
 typedef struct _GskRenderNode           GskRenderNode;
+typedef struct _GskColorStop            GskColorStop;
+
+struct _GskColorStop
+{
+  double offset;
+  GdkRGBA color;
+};
 
 GDK_AVAILABLE_IN_3_90
 GType gsk_render_node_get_type (void) G_GNUC_CONST;
@@ -54,6 +61,19 @@ GskRenderNode *         gsk_texture_node_new                    (GskTexture
                                                                  const graphene_rect_t    *bounds);
 
 GDK_AVAILABLE_IN_3_90
+GskRenderNode *         gsk_linear_gradient_node_new            (const graphene_rect_t    *bounds,
+                                                                 const graphene_point_t   *start,
+                                                                 const graphene_point_t   *end,
+                                                                 const GskColorStop       *color_stops,
+                                                                 gsize                     n_color_stops);
+GDK_AVAILABLE_IN_3_90
+GskRenderNode *         gsk_repeating_linear_gradient_node_new  (const graphene_rect_t    *bounds,
+                                                                 const graphene_point_t   *start,
+                                                                 const graphene_point_t   *end,
+                                                                 const GskColorStop       *color_stops,
+                                                                 gsize                     n_color_stops);
+
+GDK_AVAILABLE_IN_3_90
 GskRenderNode *         gsk_cairo_node_new                      (const graphene_rect_t    *bounds);
 GDK_AVAILABLE_IN_3_90
 cairo_t *               gsk_cairo_node_get_draw_context         (GskRenderNode            *node,
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index 90f90f1..5ab0d22 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -115,6 +115,162 @@ gsk_color_node_new (const GdkRGBA         *rgba,
   return &self->render_node;
 }
 
+/*** GSK_LINEAR_GRADIENT_NODE ***/
+
+typedef struct _GskLinearGradientNode GskLinearGradientNode;
+
+struct _GskLinearGradientNode
+{
+  GskRenderNode render_node;
+
+  graphene_rect_t bounds;
+
+  graphene_point_t start;
+  graphene_point_t end;
+
+  GskColorStop *stops;
+  gsize n_stops;
+};
+
+static void
+gsk_linear_gradient_node_finalize (GskRenderNode *node)
+{
+  GskLinearGradientNode *self = (GskLinearGradientNode *) node;
+
+  g_free (self->stops);
+}
+
+static void
+gsk_linear_gradient_node_make_immutable (GskRenderNode *node)
+{
+}
+
+static void
+gsk_linear_gradient_node_draw (GskRenderNode *node,
+                               cairo_t       *cr)
+{
+  GskLinearGradientNode *self = (GskLinearGradientNode *) node;
+  cairo_pattern_t *pattern;
+  gsize i;
+
+  pattern = cairo_pattern_create_linear (self->start.x, self->start.y,
+                                         self->end.x, self->end.y);
+
+  if (gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE)
+    cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+
+  for (i = 0; i < self->n_stops; i++)
+    {
+      cairo_pattern_add_color_stop_rgba (pattern,
+                                         self->stops[i].offset,
+                                         self->stops[i].color.red,
+                                         self->stops[i].color.green,
+                                         self->stops[i].color.blue,
+                                         self->stops[i].color.alpha);
+    }
+
+  cairo_set_source (cr, pattern);
+  cairo_pattern_destroy (pattern);
+
+  cairo_rectangle (cr,
+                   self->bounds.origin.x, self->bounds.origin.y,
+                   self->bounds.size.width, self->bounds.size.height);
+  cairo_fill (cr);
+}
+
+static void
+gsk_linear_gradient_node_get_bounds (GskRenderNode   *node,
+                                     graphene_rect_t *bounds)
+{
+  GskLinearGradientNode *self = (GskLinearGradientNode *) node;
+
+  graphene_rect_init_from_rect (bounds, &self->bounds); 
+}
+
+static const GskRenderNodeClass GSK_LINEAR_GRADIENT_NODE_CLASS = {
+  GSK_LINEAR_GRADIENT_NODE,
+  sizeof (GskLinearGradientNode),
+  "GskLinearGradientNode",
+  gsk_linear_gradient_node_finalize,
+  gsk_linear_gradient_node_make_immutable,
+  gsk_linear_gradient_node_draw,
+  gsk_linear_gradient_node_get_bounds
+};
+
+static const GskRenderNodeClass GSK_REPEATING_LINEAR_GRADIENT_NODE_CLASS = {
+  GSK_REPEATING_LINEAR_GRADIENT_NODE,
+  sizeof (GskLinearGradientNode),
+  "GskLinearGradientNode",
+  gsk_linear_gradient_node_finalize,
+  gsk_linear_gradient_node_make_immutable,
+  gsk_linear_gradient_node_draw,
+  gsk_linear_gradient_node_get_bounds
+};
+
+/**
+ * gsk_linear_gradient_node_new:
+ * @linear_gradient: the #GskLinearGradient
+ * @bounds: the rectangle to render the linear_gradient into
+ *
+ * Creates a #GskRenderNode that will render the given
+ * @linear_gradient into the area given by @bounds.
+ *
+ * Returns: A new #GskRenderNode
+ *
+ * Since: 3.90
+ */
+GskRenderNode *
+gsk_linear_gradient_node_new (const graphene_rect_t  *bounds,
+                              const graphene_point_t *start,
+                              const graphene_point_t *end,
+                              const GskColorStop     *color_stops,
+                              gsize                   n_color_stops)
+{
+  GskLinearGradientNode *self;
+
+  g_return_val_if_fail (bounds != NULL, NULL);
+  g_return_val_if_fail (start != NULL, NULL);
+  g_return_val_if_fail (end != NULL, NULL);
+  g_return_val_if_fail (color_stops != NULL, NULL);
+
+  self = (GskLinearGradientNode *) gsk_render_node_new (&GSK_LINEAR_GRADIENT_NODE_CLASS);
+
+  graphene_rect_init_from_rect (&self->bounds, bounds);
+  graphene_point_init_from_point (&self->start, start);
+  graphene_point_init_from_point (&self->end, end);
+
+  self->stops = g_memdup (color_stops, sizeof (GskColorStop) * n_color_stops);
+  self->n_stops = n_color_stops;
+
+  return &self->render_node;
+}
+
+GskRenderNode *
+gsk_repeating_linear_gradient_node_new (const graphene_rect_t  *bounds,
+                                        const graphene_point_t *start,
+                                        const graphene_point_t *end,
+                                        const GskColorStop     *color_stops,
+                                        gsize                   n_color_stops)
+{
+  GskLinearGradientNode *self;
+
+  g_return_val_if_fail (bounds != NULL, NULL);
+  g_return_val_if_fail (start != NULL, NULL);
+  g_return_val_if_fail (end != NULL, NULL);
+  g_return_val_if_fail (color_stops != NULL, NULL);
+
+  self = (GskLinearGradientNode *) gsk_render_node_new (&GSK_REPEATING_LINEAR_GRADIENT_NODE_CLASS);
+
+  graphene_rect_init_from_rect (&self->bounds, bounds);
+  graphene_point_init_from_point (&self->start, start);
+  graphene_point_init_from_point (&self->end, end);
+
+  self->stops = g_memdup (color_stops, sizeof (GskColorStop) * n_color_stops);
+  self->n_stops = n_color_stops;
+
+  return &self->render_node;
+}
+
 /*** GSK_TEXTURE_NODE ***/
 
 typedef struct _GskTextureNode GskTextureNode;
diff --git a/gtk/gtkcssimagelinear.c b/gtk/gtkcssimagelinear.c
index 07ab3ea..0e415d6 100644
--- a/gtk/gtkcssimagelinear.c
+++ b/gtk/gtkcssimagelinear.c
@@ -128,19 +128,22 @@ gtk_css_image_linear_compute_start_point (double angle_in_degrees,
 }
                                          
 static void
-gtk_css_image_linear_draw (GtkCssImage        *image,
-                           cairo_t            *cr,
-                           double              width,
-                           double              height)
+gtk_css_image_linear_snapshot (GtkCssImage        *image,
+                               GtkSnapshot        *snapshot,
+                               double              width,
+                               double              height)
 {
   GtkCssImageLinear *linear = GTK_CSS_IMAGE_LINEAR (image);
-  cairo_pattern_t *pattern;
+  GskColorStop stops[linear->stops->len];
+  GskRenderNode *node;
+  double off_x, off_y; /* snapshot offset */
   double angle; /* actual angle of the gradiant line in degrees */
   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] */
   double offset;
   int i, last;
+  char *name;
 
   if (linear->side)
     {
@@ -177,12 +180,6 @@ gtk_css_image_linear_draw (GtkCssImage        *image,
 
   length = sqrt (x * x + y * y);
   gtk_css_image_linear_get_start_end (linear, length, &start, &end);
-  pattern = 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 (pattern, CAIRO_EXTEND_REPEAT);
-  else
-    cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
 
   offset = start;
   last = -1;
@@ -209,31 +206,45 @@ gtk_css_image_linear_draw (GtkCssImage        *image,
       step = (pos - offset) / (i - last);
       for (last = last + 1; last <= i; last++)
         {
-          const GdkRGBA *rgba;
-
           stop = &g_array_index (linear->stops, GtkCssImageLinearColorStop, last);
 
-          rgba = _gtk_css_rgba_value_get_rgba (stop->color);
           offset += step;
 
-          cairo_pattern_add_color_stop_rgba (pattern,
-                                             (offset - start) / (end - start),
-                                             rgba->red,
-                                             rgba->green,
-                                             rgba->blue,
-                                             rgba->alpha);
+          stops[last].offset = (offset - start) / (end - start);
+          stops[last].color = *_gtk_css_rgba_value_get_rgba (stop->color);
         }
 
       offset = pos;
       last = i;
     }
 
-  cairo_rectangle (cr, 0, 0, width, height);
-  cairo_translate (cr, width / 2, height / 2);
-  cairo_set_source (cr, pattern);
-  cairo_fill (cr);
+  gtk_snapshot_get_offset (snapshot, &off_x, &off_y);
+
+  if (linear->repeating)
+    {
+      node = gsk_repeating_linear_gradient_node_new (
+          &GRAPHENE_RECT_INIT (off_x, off_y, width, height),
+          &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (start - 0.5), off_y + height / 2 + y * (start - 
0.5)),
+          &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (end - 0.5),   off_y + height / 2 + y * (end - 0.5)),
+          stops,
+          linear->stops->len);
+    }
+  else
+    {
+      node = gsk_linear_gradient_node_new (
+          &GRAPHENE_RECT_INIT (off_x, off_y, width, height),
+          &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (start - 0.5), off_y + height / 2 + y * (start - 
0.5)),
+          &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (end - 0.5),   off_y + height / 2 + y * (end - 0.5)),
+          stops,
+          linear->stops->len);
+    }
+  name = g_strdup_printf ("%sLinearGradient<%ustops>", linear->repeating ? "Repeating" : "", 
linear->stops->len);
+  gsk_render_node_set_name (node, name);
+  g_free (name);
+
+  gtk_snapshot_append_node (snapshot, node);
 
-  cairo_pattern_destroy (pattern);
+  gsk_render_node_unref (node);
 }
 
 
@@ -604,7 +615,7 @@ _gtk_css_image_linear_class_init (GtkCssImageLinearClass *klass)
   GtkCssImageClass *image_class = GTK_CSS_IMAGE_CLASS (klass);
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-  image_class->draw = gtk_css_image_linear_draw;
+  image_class->snapshot = gtk_css_image_linear_snapshot;
   image_class->parse = gtk_css_image_linear_parse;
   image_class->print = gtk_css_image_linear_print;
   image_class->compute = gtk_css_image_linear_compute;
diff --git a/gtk/inspector/gtktreemodelrendernode.c b/gtk/inspector/gtktreemodelrendernode.c
index 5426250..6ac5b32 100644
--- a/gtk/inspector/gtktreemodelrendernode.c
+++ b/gtk/inspector/gtktreemodelrendernode.c
@@ -525,6 +525,8 @@ append_node (GtkTreeModelRenderNode *nodemodel,
     case GSK_CAIRO_NODE:
     case GSK_TEXTURE_NODE:
     case GSK_COLOR_NODE:
+    case GSK_LINEAR_GRADIENT_NODE:
+    case GSK_REPEATING_LINEAR_GRADIENT_NODE:
       /* no children */
       break;
 


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