[gtk+/wip/baedert/gl: 87/111] gl renderer: Use one function per node-type



commit 20b16e255076c30c75bcff7be9094e18b7d7e500
Author: Timm Bäder <mail baedert org>
Date:   Fri Dec 8 13:12:43 2017 +0100

    gl renderer: Use one function per node-type
    
    So a profiler can actually tell me what's slow and not just point at
    _add_render_ops in all cases.

 gsk/gl/gskglrenderer.c |  854 ++++++++++++++++++++++++++----------------------
 1 files changed, 468 insertions(+), 386 deletions(-)
---
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index 0555da7..55fea12 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -82,6 +82,15 @@ font_has_color_glyphs (const PangoFont *font)
   return has_color;
 }
 
+static void
+get_gl_scaling_filters (GskRenderNode *node,
+                        int           *min_filter_r,
+                        int           *mag_filter_r)
+{
+  *min_filter_r = GL_LINEAR;
+  *mag_filter_r = GL_LINEAR;
+}
+
 static inline void
 rounded_rect_to_floats (const GskRoundedRect *rect,
                         float                *outline,
@@ -171,6 +180,10 @@ static void add_offscreen_ops                 (GskGLRenderer   *self,
                                                GskRenderNode   *child_node,
                                                int             *texture_id,
                                                gboolean        *is_offscreen);
+static void gsk_gl_renderer_add_render_ops     (GskGLRenderer   *self,
+                                                GskRenderNode   *node,
+                                                RenderOpBuilder *builder);
+
 typedef enum
 {
   RENDER_FULL,
@@ -494,6 +507,441 @@ render_border_node (GskGLRenderer   *self,
     ops_set_clip (builder, &prev_clip);
 }
 
+static inline void
+render_color_node (GskGLRenderer       *self,
+                   GskRenderNode       *node,
+                   RenderOpBuilder     *builder,
+                   const GskQuadVertex *vertex_data)
+{
+  ops_set_program (builder, &self->color_program);
+  ops_set_color (builder, gsk_color_node_peek_color (node));
+  ops_draw (builder, vertex_data);
+}
+
+static inline void
+render_texture_node (GskGLRenderer       *self,
+                     GskRenderNode       *node,
+                     RenderOpBuilder     *builder,
+                     const GskQuadVertex *vertex_data)
+{
+  GdkTexture *texture = gsk_texture_node_get_texture (node);
+  int gl_min_filter = GL_NEAREST, gl_mag_filter = GL_NEAREST;
+  int texture_id;
+
+  get_gl_scaling_filters (node, &gl_min_filter, &gl_mag_filter);
+
+  texture_id = gsk_gl_driver_get_texture_for_texture (self->gl_driver,
+                                                      texture,
+                                                      gl_min_filter,
+                                                      gl_mag_filter);
+  ops_set_program (builder, &self->blit_program);
+  ops_set_texture (builder, texture_id);
+  ops_draw (builder, vertex_data);
+}
+
+static inline void
+render_cairo_node (GskGLRenderer       *self,
+                   GskRenderNode       *node,
+                   RenderOpBuilder     *builder,
+                   const GskQuadVertex *vertex_data)
+{
+  const cairo_surface_t *surface = gsk_cairo_node_peek_surface (node);
+  int gl_min_filter = GL_NEAREST, gl_mag_filter = GL_NEAREST;
+  int texture_id;
+
+  if (surface == NULL)
+    return;
+
+  get_gl_scaling_filters (node, &gl_min_filter, &gl_mag_filter);
+
+  texture_id = gsk_gl_driver_create_texture (self->gl_driver,
+                                             node->bounds.size.width,
+                                             node->bounds.size.height);
+  gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
+  gsk_gl_driver_init_texture_with_surface (self->gl_driver,
+                                           texture_id,
+                                           (cairo_surface_t *)surface,
+                                           gl_min_filter,
+                                           gl_mag_filter);
+  ops_set_program (builder, &self->blit_program);
+  ops_set_texture (builder, texture_id);
+  ops_draw (builder, vertex_data);
+}
+
+static inline void
+render_transform_node (GskGLRenderer   *self,
+                       GskRenderNode   *node,
+                       RenderOpBuilder *builder)
+{
+  GskRenderNode *child = gsk_transform_node_get_child (node);
+  graphene_matrix_t prev_mv;
+  graphene_matrix_t transform, transformed_mv;
+
+  graphene_matrix_init_from_matrix (&transform, gsk_transform_node_peek_transform (node));
+  graphene_matrix_multiply (&transform, &builder->current_modelview, &transformed_mv);
+  prev_mv = ops_set_modelview (builder, &transformed_mv);
+
+  gsk_gl_renderer_add_render_ops (self, child, builder);
+
+  ops_set_modelview (builder, &prev_mv);
+}
+
+static inline void
+render_opacity_node (GskGLRenderer   *self,
+                     GskRenderNode   *node,
+                     RenderOpBuilder *builder)
+{
+  float prev_opacity;
+
+  prev_opacity = ops_set_opacity (builder,
+                                  builder->current_opacity * gsk_opacity_node_get_opacity (node));
+
+  gsk_gl_renderer_add_render_ops (self, gsk_opacity_node_get_child (node), builder);
+
+  ops_set_opacity (builder, prev_opacity);
+}
+
+static inline void
+render_linear_gradient_node (GskGLRenderer       *self,
+                             GskRenderNode       *node,
+                             RenderOpBuilder     *builder,
+                             const GskQuadVertex *vertex_data)
+{
+  RenderOp op;
+  int n_color_stops = MIN (8, gsk_linear_gradient_node_get_n_color_stops (node));
+  const GskColorStop *stops = gsk_linear_gradient_node_peek_color_stops (node);
+  const graphene_point_t *start = gsk_linear_gradient_node_peek_start (node);
+  const graphene_point_t *end = gsk_linear_gradient_node_peek_end (node);
+  int i;
+
+  for (i = 0; i < n_color_stops; i ++)
+    {
+      const GskColorStop *stop = stops + i;
+
+      op.linear_gradient.color_stops[(i * 4) + 0] = stop->color.red;
+      op.linear_gradient.color_stops[(i * 4) + 1] = stop->color.green;
+      op.linear_gradient.color_stops[(i * 4) + 2] = stop->color.blue;
+      op.linear_gradient.color_stops[(i * 4) + 3] = stop->color.alpha;
+      op.linear_gradient.color_offsets[i] = stop->offset;
+    }
+
+  ops_set_program (builder, &self->linear_gradient_program);
+  op.op = OP_CHANGE_LINEAR_GRADIENT;
+  op.linear_gradient.n_color_stops = n_color_stops;
+  op.linear_gradient.start_point = *start;
+  op.linear_gradient.end_point = *end;
+  ops_add (builder, &op);
+
+  ops_draw (builder, vertex_data);
+}
+
+static inline void
+render_clip_node (GskGLRenderer   *self,
+                  GskRenderNode   *node,
+                  RenderOpBuilder *builder)
+{
+  GskRoundedRect prev_clip;
+  GskRenderNode *child = gsk_clip_node_get_child (node);
+  graphene_rect_t transformed_clip;
+  graphene_rect_t intersection;
+  GskRoundedRect child_clip;
+
+  transformed_clip = *gsk_clip_node_peek_clip (node);
+  graphene_matrix_transform_bounds (&builder->current_modelview, &transformed_clip, &transformed_clip);
+
+  graphene_rect_intersection (&transformed_clip,
+                              &builder->current_clip.bounds,
+                              &intersection);
+
+  gsk_rounded_rect_init_from_rect (&child_clip, &intersection, 0.0f);
+
+  prev_clip = ops_set_clip (builder, &child_clip);
+  gsk_gl_renderer_add_render_ops (self, child, builder);
+  ops_set_clip (builder, &prev_clip);
+}
+
+static inline void
+render_rounded_clip_node (GskGLRenderer   *self,
+                          GskRenderNode   *node,
+                          RenderOpBuilder *builder)
+{
+  GskRoundedRect prev_clip;
+  GskRenderNode *child = gsk_rounded_clip_node_get_child (node);
+  const GskRoundedRect *rounded_clip = gsk_rounded_clip_node_peek_clip (node);
+  graphene_rect_t transformed_clip;
+  graphene_rect_t intersection;
+  GskRoundedRect child_clip;
+
+  transformed_clip = rounded_clip->bounds;
+  graphene_matrix_transform_bounds (&builder->current_modelview, &transformed_clip, &transformed_clip);
+
+  graphene_rect_intersection (&transformed_clip, &builder->current_clip.bounds,
+                              &intersection);
+  gsk_rounded_rect_init (&child_clip, &intersection,
+                         &rounded_clip->corner[0],
+                         &rounded_clip->corner[1],
+                         &rounded_clip->corner[2],
+                         &rounded_clip->corner[3]);
+
+  prev_clip = ops_set_clip (builder, &child_clip);
+  gsk_gl_renderer_add_render_ops (self, child, builder);
+  ops_set_clip (builder, &prev_clip);
+}
+
+static inline void
+render_color_matrix_node (GskGLRenderer       *self,
+                          GskRenderNode       *node,
+                          RenderOpBuilder     *builder,
+                          const GskQuadVertex *vertex_data)
+{
+  const float min_x = node->bounds.origin.x;
+  const float min_y = node->bounds.origin.y;
+  const float max_x = min_x + node->bounds.size.width;
+  const float max_y = min_y + node->bounds.size.height;
+  int texture_id;
+  gboolean is_offscreen;
+
+  add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y,
+                     gsk_color_matrix_node_get_child (node),
+                     &texture_id, &is_offscreen);
+
+  ops_set_program (builder, &self->color_matrix_program);
+  ops_set_color_matrix (builder,
+                        gsk_color_matrix_node_peek_color_matrix (node),
+                        gsk_color_matrix_node_peek_color_offset (node));
+
+  ops_set_texture (builder, texture_id);
+
+  if (is_offscreen)
+    {
+      GskQuadVertex vertex_data[GL_N_VERTICES] = {
+        { { min_x, min_y }, { 0, 1 }, },
+        { { min_x, max_y }, { 0, 0 }, },
+        { { max_x, min_y }, { 1, 1 }, },
+
+        { { max_x, max_y }, { 1, 0 }, },
+        { { min_x, max_y }, { 0, 0 }, },
+        { { max_x, min_y }, { 1, 1 }, },
+      };
+
+      ops_draw (builder, vertex_data);
+    }
+  else
+    {
+      ops_draw (builder, vertex_data);
+    }
+}
+
+static inline void
+render_blur_node (GskGLRenderer       *self,
+                  GskRenderNode       *node,
+                  RenderOpBuilder     *builder,
+                  const GskQuadVertex *vertex_data)
+{
+  const float min_x = node->bounds.origin.x;
+  const float min_y = node->bounds.origin.y;
+  const float max_x = min_x + node->bounds.size.width;
+  const float max_y = min_y + node->bounds.size.height;
+  int texture_id;
+  gboolean is_offscreen;
+  RenderOp op;
+  add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y,
+                     gsk_blur_node_get_child (node),
+                     &texture_id, &is_offscreen);
+
+  ops_set_program (builder, &self->blur_program);
+  op.op = OP_CHANGE_BLUR;
+  graphene_size_init_from_size (&op.blur.size, &node->bounds.size);
+  op.blur.radius = gsk_blur_node_get_radius (node);
+  ops_add (builder, &op);
+
+  ops_set_texture (builder, texture_id);
+
+  if (is_offscreen)
+    {
+      GskQuadVertex vertex_data[GL_N_VERTICES] = {
+        { { min_x, min_y }, { 0, 1 }, },
+        { { min_x, max_y }, { 0, 0 }, },
+        { { max_x, min_y }, { 1, 1 }, },
+
+        { { max_x, max_y }, { 1, 0 }, },
+        { { min_x, max_y }, { 0, 0 }, },
+        { { max_x, min_y }, { 1, 1 }, },
+      };
+
+      ops_draw (builder, vertex_data);
+    }
+  else
+    {
+      ops_draw (builder, vertex_data);
+    }
+}
+
+static inline void
+render_inset_shadow_node (GskGLRenderer       *self,
+                          GskRenderNode       *node,
+                          RenderOpBuilder     *builder,
+                          const GskQuadVertex *vertex_data)
+{
+  RenderOp op;
+
+  /* TODO: Implement blurred inset shadows as well */
+  if (gsk_inset_shadow_node_get_blur_radius (node) > 0)
+    {
+      render_fallback_node (self, node, builder, vertex_data);
+      return;
+    }
+
+  op.op = OP_CHANGE_INSET_SHADOW;
+  rgba_to_float (gsk_inset_shadow_node_peek_color (node), op.inset_shadow.color);
+  rounded_rect_to_floats (gsk_inset_shadow_node_peek_outline (node),
+                          op.inset_shadow.outline,
+                          op.inset_shadow.corner_widths,
+                          op.inset_shadow.corner_heights);
+  op.inset_shadow.radius = gsk_inset_shadow_node_get_blur_radius (node);
+  op.inset_shadow.spread = gsk_inset_shadow_node_get_spread (node);
+  op.inset_shadow.offset[0] = gsk_inset_shadow_node_get_dx (node);
+  op.inset_shadow.offset[1] = -gsk_inset_shadow_node_get_dy (node);
+
+  ops_set_program (builder, &self->inset_shadow_program);
+  ops_add (builder, &op);
+  ops_draw (builder, vertex_data);
+}
+
+static inline void
+render_outset_shadow_node (GskGLRenderer       *self,
+                           GskRenderNode       *node,
+                           RenderOpBuilder     *builder,
+                           const GskQuadVertex *vertex_data)
+{
+  RenderOp op;
+
+  /* TODO: Implement blurred outset shadows as well */
+  if (gsk_outset_shadow_node_get_blur_radius (node) > 0)
+    {
+      render_fallback_node (self, node, builder, vertex_data);
+      return;
+    }
+
+  op.op = OP_CHANGE_OUTSET_SHADOW;
+  rgba_to_float (gsk_outset_shadow_node_peek_color (node), op.outset_shadow.color);
+  rounded_rect_to_floats (gsk_outset_shadow_node_peek_outline (node),
+                          op.outset_shadow.outline,
+                          op.outset_shadow.corner_widths,
+                          op.outset_shadow.corner_heights);
+  op.outset_shadow.radius = gsk_outset_shadow_node_get_blur_radius (node);
+  op.outset_shadow.spread = gsk_outset_shadow_node_get_spread (node);
+  op.outset_shadow.offset[0] = gsk_outset_shadow_node_get_dx (node);
+  op.outset_shadow.offset[1] = -gsk_outset_shadow_node_get_dy (node);
+
+  ops_set_program (builder, &self->outset_shadow_program);
+  ops_add (builder, &op);
+  ops_draw (builder, vertex_data);
+}
+
+static inline void
+render_shadow_node (GskGLRenderer       *self,
+                    GskRenderNode       *node,
+                    RenderOpBuilder     *builder,
+                    const GskQuadVertex *vertex_data)
+{
+  float min_x = node->bounds.origin.x;
+  float min_y = node->bounds.origin.y;
+  float max_x = min_x + node->bounds.size.width;
+  float max_y = min_y + node->bounds.size.height;
+  GskRenderNode *original_child = gsk_shadow_node_get_child (node);
+  GskRenderNode *shadow_child = original_child;
+  gsize n_shadows = gsk_shadow_node_get_n_shadows (node);
+  guint i;
+
+  /* TODO: Implement blurred shadow nodes */;
+  for (i = 0; i < n_shadows; i ++)
+    {
+      const GskShadow *shadow = gsk_shadow_node_peek_shadow (node, i);
+
+      if (shadow->radius > 0)
+        {
+          render_fallback_node (self, node, builder, vertex_data);
+          return;
+        }
+    }
+
+  /* Shadow nodes recolor every pixel of the source texture, but leave the alpha in tact.
+   * If the child is a color matrix node that doesn't touch the alpha, we can throw that away. */
+  if (gsk_render_node_get_node_type (shadow_child) == GSK_COLOR_MATRIX_NODE &&
+      !color_matrix_modifies_alpha (shadow_child))
+    {
+      shadow_child = gsk_color_matrix_node_get_child (shadow_child);
+    }
+
+  for (i = 0; i < n_shadows; i ++)
+    {
+      const GskShadow *shadow = gsk_shadow_node_peek_shadow (node, i);
+      int texture_id;
+      gboolean is_offscreen;
+      float dx, dy;
+
+      g_assert (shadow->radius <= 0);
+
+      if (gsk_render_node_get_node_type (shadow_child) == GSK_TEXT_NODE)
+        {
+          render_text_node (self, shadow_child, builder, &shadow->color, TRUE,
+                            shadow->dx, shadow->dy);
+          continue;
+        }
+
+      add_offscreen_ops (self, builder,
+                         dx + min_x, dx + max_x, dy + min_y, dy + max_y,
+                         shadow_child, &texture_id, &is_offscreen);
+
+      ops_set_program (builder, &self->shadow_program);
+      ops_set_color (builder, &shadow->color);
+      ops_set_texture (builder, texture_id);
+
+      dx = shadow->dx;
+      dy = shadow->dy;
+
+      if (is_offscreen)
+        {
+          const GskQuadVertex vertex_data[GL_N_VERTICES] = {
+            { { dx + min_x, dy + min_y }, { 0, 1 }, },
+            { { dx + min_x, dy + max_y }, { 0, 0 }, },
+            { { dx + max_x, dy + min_y }, { 1, 1 }, },
+
+            { { dx + max_x, dy + max_y }, { 1, 0 }, },
+            { { dx + min_x, dy + max_y }, { 0, 0 }, },
+            { { dx + max_x, dy + min_y }, { 1, 1 }, },
+          };
+          ops_draw (builder, vertex_data);
+
+        }
+      else
+        {
+          min_x = shadow_child->bounds.origin.x;
+          min_y = shadow_child->bounds.origin.y;
+          max_x = min_x + shadow_child->bounds.size.width;
+          max_y = min_y + shadow_child->bounds.size.height;
+
+          /* XXX We are inside a loop and the 4 lines above modify min_x/min_y/...
+           * so this is potentially wrong for >1 shadow. */
+          const GskQuadVertex vertex_data[GL_N_VERTICES] = {
+            { { dx + min_x, dy + min_y }, { 0, 0 }, },
+            { { dx + min_x, dy + max_y }, { 0, 1 }, },
+            { { dx + max_x, dy + min_y }, { 1, 0 }, },
+
+            { { dx + max_x, dy + max_y }, { 1, 1 }, },
+            { { dx + min_x, dy + max_y }, { 0, 1 }, },
+            { { dx + max_x, dy + min_y }, { 1, 0 }, },
+          };
+
+          ops_draw (builder, vertex_data);
+        }
+    }
+
+  /* Now draw the child normally */
+  gsk_gl_renderer_add_render_ops (self, original_child, builder);
+}
+
 static void
 gsk_gl_renderer_dispose (GObject *gobject)
 {
@@ -831,14 +1279,6 @@ gsk_gl_renderer_resize_viewport (GskGLRenderer         *self,
 }
 
 
-static void
-get_gl_scaling_filters (GskRenderNode *node,
-                        int           *min_filter_r,
-                        int           *mag_filter_r)
-{
-  *min_filter_r = GL_LINEAR;
-  *mag_filter_r = GL_LINEAR;
-}
 
 static void
 gsk_gl_renderer_clear_tree (GskGLRenderer *self)
@@ -919,10 +1359,10 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer   *self,
                                 GskRenderNode   *node,
                                 RenderOpBuilder *builder)
 {
-  float min_x = node->bounds.origin.x;
-  float min_y = node->bounds.origin.y;
-  float max_x = min_x + node->bounds.size.width;
-  float max_y = min_y + node->bounds.size.height;
+  const float min_x = node->bounds.origin.x;
+  const float min_y = node->bounds.origin.y;
+  const float max_x = min_x + node->bounds.size.width;
+  const float max_y = min_y + node->bounds.size.height;
 
   /* Default vertex data */
   const GskQuadVertex vertex_data[GL_N_VERTICES] = {
@@ -960,422 +1400,64 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer   *self,
     break;
 
     case GSK_COLOR_NODE:
-      {
-        ops_set_program (builder, &self->color_program);
-        ops_set_color (builder, gsk_color_node_peek_color (node));
-        ops_draw (builder, vertex_data);
-      }
+      render_color_node (self, node, builder, vertex_data);
     break;
 
     case GSK_TEXTURE_NODE:
-      {
-        GdkTexture *texture = gsk_texture_node_get_texture (node);
-        int gl_min_filter = GL_NEAREST, gl_mag_filter = GL_NEAREST;
-        int texture_id;
-
-        get_gl_scaling_filters (node, &gl_min_filter, &gl_mag_filter);
-
-        texture_id = gsk_gl_driver_get_texture_for_texture (self->gl_driver,
-                                                            texture,
-                                                            gl_min_filter,
-                                                            gl_mag_filter);
-        ops_set_program (builder, &self->blit_program);
-        ops_set_texture (builder, texture_id);
-        ops_draw (builder, vertex_data);
-      }
+      render_texture_node (self, node, builder, vertex_data);
     break;
 
     case GSK_CAIRO_NODE:
-      {
-        const cairo_surface_t *surface = gsk_cairo_node_peek_surface (node);
-        int gl_min_filter = GL_NEAREST, gl_mag_filter = GL_NEAREST;
-        int texture_id;
-
-        if (surface == NULL)
-          return;
-
-        get_gl_scaling_filters (node, &gl_min_filter, &gl_mag_filter);
-
-        texture_id = gsk_gl_driver_create_texture (self->gl_driver,
-                                                   max_x - min_x,
-                                                   max_y - min_y);
-        gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
-        gsk_gl_driver_init_texture_with_surface (self->gl_driver,
-                                                 texture_id,
-                                                 (cairo_surface_t *)surface,
-                                                 gl_min_filter,
-                                                 gl_mag_filter);
-        ops_set_program (builder, &self->blit_program);
-        ops_set_texture (builder, texture_id);
-        ops_draw (builder, vertex_data);
-      }
+      render_cairo_node (self, node, builder, vertex_data);
     break;
 
     case GSK_TRANSFORM_NODE:
-      {
-        GskRenderNode *child = gsk_transform_node_get_child (node);
-        graphene_matrix_t prev_mv;
-        graphene_matrix_t transform, transformed_mv;
-
-        graphene_matrix_init_from_matrix (&transform, gsk_transform_node_peek_transform (node));
-        graphene_matrix_multiply (&transform, &builder->current_modelview, &transformed_mv);
-        prev_mv = ops_set_modelview (builder, &transformed_mv);
-
-        gsk_gl_renderer_add_render_ops (self, child, builder);
-
-        ops_set_modelview (builder, &prev_mv);
-      }
+      render_transform_node (self, node, builder);
     break;
 
     case GSK_OPACITY_NODE:
-      {
-        float prev_opacity;
-
-        prev_opacity = ops_set_opacity (builder,
-                                        builder->current_opacity * gsk_opacity_node_get_opacity (node));
-
-        gsk_gl_renderer_add_render_ops (self, gsk_opacity_node_get_child (node), builder);
-
-        ops_set_opacity (builder, prev_opacity);
-      }
+      render_opacity_node (self, node, builder);
     break;
 
     case GSK_LINEAR_GRADIENT_NODE:
-      {
-        RenderOp op;
-        int n_color_stops = MIN (8, gsk_linear_gradient_node_get_n_color_stops (node));
-        const GskColorStop *stops = gsk_linear_gradient_node_peek_color_stops (node);
-        const graphene_point_t *start = gsk_linear_gradient_node_peek_start (node);
-        const graphene_point_t *end = gsk_linear_gradient_node_peek_end (node);
-        int i;
-
-        for (i = 0; i < n_color_stops; i ++)
-          {
-            const GskColorStop *stop = stops + i;
-
-            op.linear_gradient.color_stops[(i * 4) + 0] = stop->color.red;
-            op.linear_gradient.color_stops[(i * 4) + 1] = stop->color.green;
-            op.linear_gradient.color_stops[(i * 4) + 2] = stop->color.blue;
-            op.linear_gradient.color_stops[(i * 4) + 3] = stop->color.alpha;
-            op.linear_gradient.color_offsets[i] = stop->offset;
-          }
-
-        ops_set_program (builder, &self->linear_gradient_program);
-        op.op = OP_CHANGE_LINEAR_GRADIENT;
-        op.linear_gradient.n_color_stops = n_color_stops;
-        op.linear_gradient.start_point = *start;
-        op.linear_gradient.end_point = *end;
-        ops_add (builder, &op);
-
-        ops_draw (builder, vertex_data);
-      }
+      render_linear_gradient_node (self, node, builder, vertex_data);
     break;
 
     case GSK_CLIP_NODE:
-      {
-        GskRoundedRect prev_clip;
-        GskRenderNode *child = gsk_clip_node_get_child (node);
-        graphene_rect_t transformed_clip;
-        graphene_rect_t intersection;
-        GskRoundedRect child_clip;
-
-        transformed_clip = *gsk_clip_node_peek_clip (node);
-        graphene_matrix_transform_bounds (&builder->current_modelview, &transformed_clip, &transformed_clip);
-
-        graphene_rect_intersection (&transformed_clip,
-                                    &builder->current_clip.bounds,
-                                    &intersection);
-
-        gsk_rounded_rect_init_from_rect (&child_clip, &intersection, 0.0f);
-
-        prev_clip = ops_set_clip (builder, &child_clip);
-        gsk_gl_renderer_add_render_ops (self, child, builder);
-        ops_set_clip (builder, &prev_clip);
-      }
+      render_clip_node (self, node, builder);
     break;
 
     case GSK_ROUNDED_CLIP_NODE:
-      {
-        GskRoundedRect prev_clip;
-        GskRenderNode *child = gsk_rounded_clip_node_get_child (node);
-        const GskRoundedRect *rounded_clip = gsk_rounded_clip_node_peek_clip (node);
-        graphene_rect_t transformed_clip;
-        graphene_rect_t intersection;
-        GskRoundedRect child_clip;
-
-        transformed_clip = rounded_clip->bounds;
-        graphene_matrix_transform_bounds (&builder->current_modelview, &transformed_clip, &transformed_clip);
-
-        graphene_rect_intersection (&transformed_clip, &builder->current_clip.bounds,
-                                    &intersection);
-        gsk_rounded_rect_init (&child_clip, &intersection,
-                               &rounded_clip->corner[0],
-                               &rounded_clip->corner[1],
-                               &rounded_clip->corner[2],
-                               &rounded_clip->corner[3]);
-
-        prev_clip = ops_set_clip (builder, &child_clip);
-        gsk_gl_renderer_add_render_ops (self, child, builder);
-        ops_set_clip (builder, &prev_clip);
-      }
+      render_rounded_clip_node (self, node, builder);
     break;
 
     case GSK_TEXT_NODE:
-      {
-        render_text_node (self, node, builder,
-                          gsk_text_node_peek_color (node), FALSE, 0, 0);
-      }
+      render_text_node (self, node, builder,
+                        gsk_text_node_peek_color (node), FALSE, 0, 0);
     break;
 
     case GSK_COLOR_MATRIX_NODE:
-      {
-        int texture_id;
-        gboolean is_offscreen;
-
-        add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y,
-                           gsk_color_matrix_node_get_child (node),
-                           &texture_id, &is_offscreen);
-
-        ops_set_program (builder, &self->color_matrix_program);
-        ops_set_color_matrix (builder,
-                              gsk_color_matrix_node_peek_color_matrix (node),
-                              gsk_color_matrix_node_peek_color_offset (node));
-
-        ops_set_texture (builder, texture_id);
-
-        if (is_offscreen)
-          {
-            GskQuadVertex vertex_data[GL_N_VERTICES] = {
-              { { min_x, min_y }, { 0, 1 }, },
-              { { min_x, max_y }, { 0, 0 }, },
-              { { max_x, min_y }, { 1, 1 }, },
-
-              { { max_x, max_y }, { 1, 0 }, },
-              { { min_x, max_y }, { 0, 0 }, },
-              { { max_x, min_y }, { 1, 1 }, },
-            };
-
-            ops_draw (builder, vertex_data);
-          }
-        else
-          {
-            ops_draw (builder, vertex_data);
-          }
-
-      }
+      render_color_matrix_node (self, node, builder, vertex_data);
     break;
 
     case GSK_BLUR_NODE:
-      {
-        int texture_id;
-        gboolean is_offscreen;
-        RenderOp op;
-        add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y,
-                           gsk_blur_node_get_child (node),
-                           &texture_id, &is_offscreen);
-
-        ops_set_program (builder, &self->blur_program);
-        op.op = OP_CHANGE_BLUR;
-        graphene_size_init_from_size (&op.blur.size, &node->bounds.size);
-        op.blur.radius = gsk_blur_node_get_radius (node);
-        ops_add (builder, &op);
-
-        ops_set_texture (builder, texture_id);
-
-        if (is_offscreen)
-          {
-            GskQuadVertex vertex_data[GL_N_VERTICES] = {
-              { { min_x, min_y }, { 0, 1 }, },
-              { { min_x, max_y }, { 0, 0 }, },
-              { { max_x, min_y }, { 1, 1 }, },
-
-              { { max_x, max_y }, { 1, 0 }, },
-              { { min_x, max_y }, { 0, 0 }, },
-              { { max_x, min_y }, { 1, 1 }, },
-            };
-
-            ops_draw (builder, vertex_data);
-          }
-        else
-          {
-            ops_draw (builder, vertex_data);
-          }
-      }
+      render_blur_node (self, node, builder, vertex_data);
     break;
 
     case GSK_INSET_SHADOW_NODE:
-      {
-        RenderOp op;
-
-        /* TODO: Implement blurred inset shadows as well */
-        if (gsk_inset_shadow_node_get_blur_radius (node) > 0)
-          {
-            render_fallback_node (self, node, builder, vertex_data);
-            break;
-          }
-
-        op.op = OP_CHANGE_INSET_SHADOW;
-        rgba_to_float (gsk_inset_shadow_node_peek_color (node), op.inset_shadow.color);
-        rounded_rect_to_floats (gsk_inset_shadow_node_peek_outline (node),
-                                op.inset_shadow.outline,
-                                op.inset_shadow.corner_widths,
-                                op.inset_shadow.corner_heights);
-        op.inset_shadow.radius = gsk_inset_shadow_node_get_blur_radius (node);
-        op.inset_shadow.spread = gsk_inset_shadow_node_get_spread (node);
-        op.inset_shadow.offset[0] = gsk_inset_shadow_node_get_dx (node);
-        op.inset_shadow.offset[1] = -gsk_inset_shadow_node_get_dy (node);
-
-        ops_set_program (builder, &self->inset_shadow_program);
-        ops_add (builder, &op);
-        ops_draw (builder, vertex_data);
-      }
+      render_inset_shadow_node (self, node, builder, vertex_data);
     break;
 
     case GSK_OUTSET_SHADOW_NODE:
-      {
-        RenderOp op;
-
-        /* TODO: Implement blurred outset shadows as well */
-        if (gsk_outset_shadow_node_get_blur_radius (node) > 0)
-          {
-            render_fallback_node (self, node, builder, vertex_data);
-            break;
-          }
-
-        op.op = OP_CHANGE_OUTSET_SHADOW;
-        rgba_to_float (gsk_outset_shadow_node_peek_color (node), op.outset_shadow.color);
-        rounded_rect_to_floats (gsk_outset_shadow_node_peek_outline (node),
-                                op.outset_shadow.outline,
-                                op.outset_shadow.corner_widths,
-                                op.outset_shadow.corner_heights);
-        op.outset_shadow.radius = gsk_outset_shadow_node_get_blur_radius (node);
-        op.outset_shadow.spread = gsk_outset_shadow_node_get_spread (node);
-        op.outset_shadow.offset[0] = gsk_outset_shadow_node_get_dx (node);
-        op.outset_shadow.offset[1] = -gsk_outset_shadow_node_get_dy (node);
-
-        ops_set_program (builder, &self->outset_shadow_program);
-        ops_add (builder, &op);
-        ops_draw (builder, vertex_data);
-      }
+      render_outset_shadow_node (self, node, builder, vertex_data);
     break;
 
     case GSK_SHADOW_NODE:
-      {
-        GskRenderNode *original_child = gsk_shadow_node_get_child (node);
-        GskRenderNode *shadow_child = original_child;
-        gsize n_shadows = gsk_shadow_node_get_n_shadows (node);
-        guint i;
-
-        /* TODO: Implement blurred shadow nodes */;
-        for (i = 0; i < n_shadows; i ++)
-          {
-            const GskShadow *shadow = gsk_shadow_node_peek_shadow (node, i);
-
-            if (shadow->radius > 0)
-              {
-                render_fallback_node (self, node, builder, vertex_data);
-                return;
-              }
-          }
-
-        /* Shadow nodes recolor every pixel of the source texture, but leave the alpha in tact.
-         * If the child is a color matrix node that doesn't touch the alpha, we can throw that away. */
-        if (gsk_render_node_get_node_type (shadow_child) == GSK_COLOR_MATRIX_NODE &&
-            !color_matrix_modifies_alpha (shadow_child))
-          {
-            shadow_child = gsk_color_matrix_node_get_child (shadow_child);
-          }
-
-        for (i = 0; i < n_shadows; i ++)
-          {
-            const GskShadow *shadow = gsk_shadow_node_peek_shadow (node, i);
-            int texture_id;
-            gboolean is_offscreen;
-            float dx, dy;
-
-            g_assert (shadow->radius <= 0);
-
-            if (gsk_render_node_get_node_type (shadow_child) == GSK_TEXT_NODE)
-              {
-                render_text_node (self, shadow_child, builder, &shadow->color, TRUE,
-                                  shadow->dx, shadow->dy);
-                continue;
-              }
-
-            add_offscreen_ops (self, builder,
-                               dx + min_x, dx + max_x, dy + min_y, dy + max_y,
-                               shadow_child, &texture_id, &is_offscreen);
-
-            ops_set_program (builder, &self->shadow_program);
-            ops_set_color (builder, &shadow->color);
-            ops_set_texture (builder, texture_id);
-
-            dx = shadow->dx;
-            dy = shadow->dy;
-
-            if (is_offscreen)
-              {
-                const GskQuadVertex vertex_data[GL_N_VERTICES] = {
-                  { { dx + min_x, dy + min_y }, { 0, 1 }, },
-                  { { dx + min_x, dy + max_y }, { 0, 0 }, },
-                  { { dx + max_x, dy + min_y }, { 1, 1 }, },
-
-                  { { dx + max_x, dy + max_y }, { 1, 0 }, },
-                  { { dx + min_x, dy + max_y }, { 0, 0 }, },
-                  { { dx + max_x, dy + min_y }, { 1, 1 }, },
-                };
-                ops_draw (builder, vertex_data);
-              }
-            else
-              {
-                min_x = shadow_child->bounds.origin.x;
-                min_y = shadow_child->bounds.origin.y;
-                max_x = min_x + shadow_child->bounds.size.width;
-                max_y = min_y + shadow_child->bounds.size.height;
-
-                /* XXX We are inside a loop and the 4 lines above modify min_x/min_y/...
-                 * so this is potentially wrong for >1 shadow. */
-                const GskQuadVertex vertex_data[GL_N_VERTICES] = {
-                  { { dx + min_x, dy + min_y }, { 0, 0 }, },
-                  { { dx + min_x, dy + max_y }, { 0, 1 }, },
-                  { { dx + max_x, dy + min_y }, { 1, 0 }, },
-
-                  { { dx + max_x, dy + max_y }, { 1, 1 }, },
-                  { { dx + min_x, dy + max_y }, { 0, 1 }, },
-                  { { dx + max_x, dy + min_y }, { 1, 0 }, },
-                };
-
-                ops_draw (builder, vertex_data);
-              }
-          }
-
-        /* Now draw the child normally */
-        gsk_gl_renderer_add_render_ops (self, original_child, builder);
-      }
+      render_shadow_node (self, node, builder, vertex_data);
     break;
 
     case GSK_BORDER_NODE:
-      {
-        /* TODO: The cairo backend is exactly as broken as the code in the following
-           function. test case:
-
-          .foo {
-            border-left:   50px solid #0f0;
-            border-top:    10px solid red;
-            border-bottom: 50px solid teal;
-            border-right:  100px solid pink;
-
-
-            border-radius: 100px; 
-            min-height:100px;
-
-            float:left;
-          }
-
-          Or, like, just circular things.
-         */
-        render_border_node (self, node, builder);
-      }
+      render_border_node (self, node, builder);
     break;
 
     case GSK_REPEATING_LINEAR_GRADIENT_NODE:


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