[gnome-shell] [StThemeNode] Make shadow helper functions semi-public



commit ba1da9deb998e3ab5e65ed4fccfd3ff173df6eaa
Author: Florian Müllner <fmuellner gnome org>
Date:   Sat Jul 24 17:41:25 2010 +0200

    [StThemeNode] Make shadow helper functions semi-public
    
    Move shadow helper functions from st-theme-node-drawing to st-private
    to make them available to widgets which want to add shadows to internal
    actors.
    Also add a new helper function for creating the shadow material from a
    ClutterActor.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=624384

 src/st/st-private.c            |  257 ++++++++++++++++++++++++++++++++++++++++
 src/st/st-private.h            |   11 ++
 src/st/st-theme-node-drawing.c |  231 +++---------------------------------
 3 files changed, 283 insertions(+), 216 deletions(-)
---
diff --git a/src/st/st-private.c b/src/st/st-private.c
index c1614b0..2376352 100644
--- a/src/st/st-private.c
+++ b/src/st/st-private.c
@@ -1,4 +1,7 @@
 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+#include <math.h>
+#include <string.h>
+
 #include "st-private.h"
 
 /**
@@ -320,3 +323,257 @@ _st_set_text_from_style (ClutterText *text,
     clutter_text_set_line_alignment (text, (PangoAlignment) align);
   }
 }
+
+
+/*****
+ * Shadows
+ *****/
+
+static gdouble *
+calculate_gaussian_kernel (gdouble   sigma,
+                           guint     n_values)
+{
+  gdouble *ret, sum;
+  gdouble exp_divisor;
+  gint half, i;
+
+  g_return_val_if_fail (sigma > 0, NULL);
+
+  half = n_values / 2;
+
+  ret = g_malloc (n_values * sizeof (gdouble));
+  sum = 0.0;
+
+  exp_divisor = 2 * sigma * sigma;
+
+  /* n_values of 1D Gauss function */
+  for (i = 0; i < n_values; i++)
+    {
+      ret[i] = exp (-(i - half) * (i - half) / exp_divisor);
+      sum += ret[i];
+    }
+
+  /* normalize */
+  for (i = 0; i < n_values; i++)
+    ret[i] /= sum;
+
+  return ret;
+}
+
+CoglHandle
+_st_create_shadow_material (StShadow   *shadow_spec,
+                            CoglHandle  src_texture)
+{
+  CoglHandle  material;
+  CoglHandle  texture;
+  guchar     *pixels_in, *pixels_out;
+  gint        width_in, height_in, rowstride_in;
+  gint        width_out, height_out, rowstride_out;
+  float       sigma;
+
+  g_return_val_if_fail (shadow_spec != NULL, COGL_INVALID_HANDLE);
+  g_return_val_if_fail (src_texture != COGL_INVALID_HANDLE,
+                        COGL_INVALID_HANDLE);
+
+  /* we use an approximation of the sigma - blur radius relationship used
+     in Firefox for doing SVG blurs; see
+     http://mxr.mozilla.org/mozilla-central/source/gfx/thebes/src/gfxBlur.cpp#280
+  */
+  sigma = shadow_spec->blur / 1.9;
+
+  width_in  = cogl_texture_get_width  (src_texture);
+  height_in = cogl_texture_get_height (src_texture);
+  rowstride_in = (width_in + 3) & ~3;
+
+  pixels_in  = g_malloc0 (rowstride_in * height_in);
+
+  cogl_texture_get_data (src_texture, COGL_PIXEL_FORMAT_A_8,
+                         rowstride_in, pixels_in);
+
+  if ((guint) shadow_spec->blur == 0)
+    {
+      width_out  = width_in;
+      height_out = height_in;
+      rowstride_out = rowstride_in;
+      pixels_out = g_memdup (pixels_in, rowstride_out * height_out);
+    }
+  else
+    {
+      gdouble *kernel;
+      guchar  *line;
+      gint     n_values, half;
+      gint     x_in, y_in, x_out, y_out, i;
+
+      n_values = (gint) 5 * sigma;
+      half = n_values / 2;
+
+      width_out  = width_in  + 2 * half;
+      height_out = height_in + 2 * half;
+      rowstride_out = (width_out + 3) & ~3;
+
+      pixels_out = g_malloc0 (rowstride_out * height_out);
+      line       = g_malloc0 (rowstride_out);
+
+      kernel = calculate_gaussian_kernel (sigma, n_values);
+
+      /* vertical blur */
+      for (x_in = 0; x_in < width_in; x_in++)
+        for (y_out = 0; y_out < height_out; y_out++)
+          {
+            guchar *pixel_in, *pixel_out;
+            gint i0, i1;
+
+            y_in = y_out - half;
+
+            /* We read from the source at 'y = y_in + i - half'; clamp the
+             * full i range [0, n_values) so that y is in [0, height_in).
+             */
+            i0 = MAX (half - y_in, 0);
+            i1 = MIN (height_in + half - y_in, n_values);
+
+            pixel_in  =  pixels_in + (y_in + i0 - half) * rowstride_in + x_in;
+            pixel_out =  pixels_out + y_out * rowstride_out + (x_in + half);
+
+            for (i = i0; i < i1; i++)
+              {
+                *pixel_out += *pixel_in * kernel[i];
+                pixel_in += rowstride_in;
+              }
+          }
+
+      /* horizontal blur */
+      for (y_out = 0; y_out < height_out; y_out++)
+        {
+          memcpy (line, pixels_out + y_out * rowstride_out, rowstride_out);
+
+          for (x_out = 0; x_out < width_out; x_out++)
+            {
+              gint i0, i1;
+              guchar *pixel_out, *pixel_in;
+
+              /* We read from the source at 'x = x_out + i - half'; clamp the
+               * full i range [0, n_values) so that x is in [0, width_out).
+               */
+              i0 = MAX (half - x_out, 0);
+              i1 = MIN (width_out + half - x_out, n_values);
+
+              pixel_in  = line + x_out + i0 - half;
+              pixel_out = pixels_out + rowstride_out * y_out + x_out;
+
+              *pixel_out = 0;
+              for (i = i0; i < i1; i++)
+                {
+                  *pixel_out += *pixel_in * kernel[i];
+                  pixel_in++;
+                }
+            }
+        }
+      g_free (kernel);
+      g_free (line);
+    }
+
+  texture = cogl_texture_new_from_data (width_out,
+                                        height_out,
+                                        COGL_TEXTURE_NONE,
+                                        COGL_PIXEL_FORMAT_A_8,
+                                        COGL_PIXEL_FORMAT_A_8,
+                                        rowstride_out,
+                                        pixels_out);
+
+  g_free (pixels_in);
+  g_free (pixels_out);
+
+  material = cogl_material_new ();
+
+  cogl_material_set_layer (material, 0, texture);
+
+  /* We set up the material to blend the shadow texture with the combine
+   * constant, but defer setting the latter until painting, so that we can
+   * take the actor's overall opacity into account. */
+  cogl_material_set_layer_combine (material, 0,
+                                   "RGBA = MODULATE (CONSTANT, TEXTURE[A])",
+                                   NULL);
+
+
+  cogl_handle_unref (texture);
+
+  return material;
+}
+
+CoglHandle
+_st_create_shadow_material_from_actor (StShadow     *shadow_spec,
+                                       ClutterActor *actor)
+{
+  CoglHandle shadow_material = COGL_INVALID_HANDLE;
+
+  if (CLUTTER_IS_TEXTURE (actor))
+    {
+      CoglHandle texture;
+
+      texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (actor));
+      shadow_material = _st_create_shadow_material (shadow_spec, texture);
+    }
+  else
+    {
+      CoglHandle buffer, offscreen;
+      ClutterActorBox box;
+      float width, height;
+
+      clutter_actor_get_allocation_box (actor, &box);
+      clutter_actor_box_get_size (&box, &width, &height);
+
+      buffer = cogl_texture_new_with_size (width,
+                                           height,
+                                           COGL_TEXTURE_NO_SLICING,
+                                           COGL_PIXEL_FORMAT_ANY);
+      offscreen = cogl_offscreen_new_to_texture (buffer);
+
+      if (offscreen != COGL_INVALID_HANDLE)
+        {
+          CoglColor clear_color;
+
+          cogl_color_set_from_4ub (&clear_color, 0, 0, 0, 0);
+          cogl_push_framebuffer (offscreen);
+          cogl_clear (&clear_color, COGL_BUFFER_BIT_COLOR);
+          cogl_ortho (0, width, height, 0, 0, 1.0);
+          clutter_actor_paint (actor);
+          cogl_pop_framebuffer ();
+          cogl_handle_unref (offscreen);
+
+          shadow_material = _st_create_shadow_material (shadow_spec, buffer);
+        }
+
+      cogl_handle_unref (buffer);
+    }
+
+  return shadow_material;
+}
+
+void
+_st_paint_shadow_with_opacity (StShadow        *shadow_spec,
+                               CoglHandle       shadow_material,
+                               ClutterActorBox *box,
+                               guint8           paint_opacity)
+{
+  ClutterActorBox shadow_box;
+  CoglColor       color;
+
+  g_return_if_fail (shadow_spec != NULL);
+  g_return_if_fail (shadow_material != COGL_INVALID_HANDLE);
+
+  st_shadow_get_box (shadow_spec, box, &shadow_box);
+
+  cogl_color_set_from_4ub (&color,
+                           shadow_spec->color.red   * paint_opacity / 255,
+                           shadow_spec->color.green * paint_opacity / 255,
+                           shadow_spec->color.blue  * paint_opacity / 255,
+                           shadow_spec->color.alpha * paint_opacity / 255);
+  cogl_color_premultiply (&color);
+
+  cogl_material_set_layer_combine_constant (shadow_material, 0, &color);
+
+  cogl_set_source (shadow_material);
+  cogl_rectangle_with_texture_coords (shadow_box.x1, shadow_box.y1,
+                                      shadow_box.x2, shadow_box.y2,
+                                      0, 0, 1, 1);
+}
diff --git a/src/st/st-private.h b/src/st/st-private.h
index 8368665..33d58d4 100644
--- a/src/st/st-private.h
+++ b/src/st/st-private.h
@@ -27,6 +27,7 @@
 #include <glib.h>
 #include "st-widget.h"
 #include "st-bin.h"
+#include "st-shadow.h"
 
 G_BEGIN_DECLS
 
@@ -72,4 +73,14 @@ void _st_allocate_fill (StWidget        *parent,
 void _st_set_text_from_style (ClutterText *text,
                               StThemeNode *theme_node);
 
+/* Helper for widgets which need to draw additional shadows */
+CoglHandle _st_create_shadow_material (StShadow   *shadow_spec,
+                                       CoglHandle  src_texture);
+CoglHandle _st_create_shadow_material_from_actor (StShadow     *shadow_spec,
+                                                  ClutterActor *actor);
+void _st_paint_shadow_with_opacity (StShadow        *shadow_spec,
+                                    CoglHandle       shadow_material,
+                                    ClutterActorBox *box,
+                                    guint8           paint_opacity);
+
 #endif /* __ST_PRIVATE_H__ */
diff --git a/src/st/st-theme-node-drawing.c b/src/st/st-theme-node-drawing.c
index ff7ea0c..2b86696 100644
--- a/src/st/st-theme-node-drawing.c
+++ b/src/st/st-theme-node-drawing.c
@@ -29,192 +29,15 @@
 */
 
 #include <stdlib.h>
-#include <string.h>
 #include <math.h>
 
 #include "st-shadow.h"
+#include "st-private.h"
 #include "st-theme-private.h"
 #include "st-theme-context.h"
 #include "st-texture-cache.h"
 #include "st-theme-node-private.h"
 
-/*****
- * Shadows
- *****/
-
-static gdouble *
-calculate_gaussian_kernel (gdouble   sigma,
-                           guint     n_values)
-{
-  gdouble *ret, sum;
-  gdouble exp_divisor;
-  gint half, i;
-
-  g_return_val_if_fail (sigma > 0, NULL);
-
-  half = n_values / 2;
-
-  ret = g_malloc (n_values * sizeof (gdouble));
-  sum = 0.0;
-
-  exp_divisor = 2 * sigma * sigma;
-
-  /* n_values of 1D Gauss function */
-  for (i = 0; i < n_values; i++)
-    {
-      ret[i] = exp (-(i - half) * (i - half) / exp_divisor);
-      sum += ret[i];
-    }
-
-  /* normalize */
-  for (i = 0; i < n_values; i++)
-    ret[i] /= sum;
-
-  return ret;
-}
-
-static CoglHandle
-create_shadow_material (StThemeNode  *node,
-                        CoglHandle    src_texture)
-{
-  CoglHandle  material;
-  CoglHandle  texture;
-  StShadow   *shadow_spec;
-  guchar     *pixels_in, *pixels_out;
-  gint        width_in, height_in, rowstride_in;
-  gint        width_out, height_out, rowstride_out;
-  float       sigma;
-
-  shadow_spec = st_theme_node_get_shadow (node);
-  if (!shadow_spec)
-    return COGL_INVALID_HANDLE;
-
-  /* we use an approximation of the sigma - blur radius relationship used
-     in Firefox for doing SVG blurs; see
-     http://mxr.mozilla.org/mozilla-central/source/gfx/thebes/src/gfxBlur.cpp#280
-  */
-  sigma = shadow_spec->blur / 1.9;
-
-  width_in  = cogl_texture_get_width  (src_texture);
-  height_in = cogl_texture_get_height (src_texture);
-  rowstride_in = (width_in + 3) & ~3;
-
-  pixels_in  = g_malloc0 (rowstride_in * height_in);
-
-  cogl_texture_get_data (src_texture, COGL_PIXEL_FORMAT_A_8,
-                         rowstride_in, pixels_in);
-
-  if ((guint) shadow_spec->blur == 0)
-    {
-      width_out  = width_in;
-      height_out = height_in;
-      rowstride_out = rowstride_in;
-      pixels_out = g_memdup (pixels_in, rowstride_out * height_out);
-    }
-  else
-    {
-      gdouble *kernel;
-      guchar  *line;
-      gint     n_values, half;
-      gint     x_in, y_in, x_out, y_out, i;
-
-      n_values = (gint) 5 * sigma;
-      half = n_values / 2;
-
-      width_out  = width_in  + 2 * half;
-      height_out = height_in + 2 * half;
-      rowstride_out = (width_out + 3) & ~3;
-
-      pixels_out = g_malloc0 (rowstride_out * height_out);
-      line       = g_malloc0 (rowstride_out);
-
-      kernel = calculate_gaussian_kernel (sigma, n_values);
-
-      /* vertical blur */
-      for (x_in = 0; x_in < width_in; x_in++)
-        for (y_out = 0; y_out < height_out; y_out++)
-          {
-            guchar *pixel_in, *pixel_out;
-            gint i0, i1;
-
-            y_in = y_out - half;
-
-            /* We read from the source at 'y = y_in + i - half'; clamp the
-             * full i range [0, n_values) so that y is in [0, height_in).
-             */
-            i0 = MAX (half - y_in, 0);
-            i1 = MIN (height_in + half - y_in, n_values);
-
-            pixel_in  =  pixels_in + (y_in + i0 - half) * rowstride_in + x_in;
-            pixel_out =  pixels_out + y_out * rowstride_out + (x_in + half);
-
-            for (i = i0; i < i1; i++)
-              {
-                *pixel_out += *pixel_in * kernel[i];
-                pixel_in += rowstride_in;
-              }
-          }
-
-      /* horizontal blur */
-      for (y_out = 0; y_out < height_out; y_out++)
-        {
-          memcpy (line, pixels_out + y_out * rowstride_out, rowstride_out);
-
-          for (x_out = 0; x_out < width_out; x_out++)
-            {
-              gint i0, i1;
-              guchar *pixel_out, *pixel_in;
-
-              /* We read from the source at 'x = x_out + i - half'; clamp the
-               * full i range [0, n_values) so that x is in [0, width_out).
-               */
-              i0 = MAX (half - x_out, 0);
-              i1 = MIN (width_out + half - x_out, n_values);
-
-              pixel_in  = line + x_out + i0 - half;
-              pixel_out = pixels_out + rowstride_out * y_out + x_out;
-
-              *pixel_out = 0;
-              for (i = i0; i < i1; i++)
-                {
-                  *pixel_out += *pixel_in * kernel[i];
-                  pixel_in++;
-                }
-            }
-        }
-      g_free (kernel);
-      g_free (line);
-    }
-
-  texture = cogl_texture_new_from_data (width_out,
-                                        height_out,
-                                        COGL_TEXTURE_NONE,
-                                        COGL_PIXEL_FORMAT_A_8,
-                                        COGL_PIXEL_FORMAT_A_8,
-                                        rowstride_out,
-                                        pixels_out);
-
-  g_free (pixels_in);
-  g_free (pixels_out);
-
-  material = cogl_material_new ();
-
-  cogl_material_set_layer (material, 0, texture);
-
-  /* We set up the material to blend the shadow texture with the combine
-   * constant, but defer setting the latter until painting, so that we can
-   * take the actor's overall opacity into account. */
-  cogl_material_set_layer_combine (material, 0,
-                                   "RGBA = MODULATE (CONSTANT, TEXTURE[A])",
-                                   NULL);
-
-
-  cogl_handle_unref (texture);
-
-  return material;
-}
-
-
 /****
  * Rounded corners
  ****/
@@ -750,7 +573,8 @@ st_theme_node_render_resources (StThemeNode   *node,
   if (shadow_spec)
     {
       if (node->border_texture != COGL_INVALID_HANDLE)
-        node->border_shadow_material = create_shadow_material (node, node->border_texture);
+        node->border_shadow_material = _st_create_shadow_material (shadow_spec,
+                                                                   node->border_texture);
       else if (node->background_color.alpha > 0 ||
                node->border_width[ST_SIDE_TOP] > 0 ||
                node->border_width[ST_SIDE_LEFT] > 0 ||
@@ -775,8 +599,8 @@ st_theme_node_render_resources (StThemeNode   *node,
               cogl_pop_framebuffer ();
               cogl_handle_unref (offscreen);
 
-              node->border_shadow_material = create_shadow_material (node,
-                                                                     buffer);
+              node->border_shadow_material = _st_create_shadow_material (shadow_spec,
+                                                                         buffer);
             }
           cogl_handle_unref (buffer);
         }
@@ -790,7 +614,8 @@ st_theme_node_render_resources (StThemeNode   *node,
 
       if (shadow_spec)
         {
-          node->background_shadow_material = create_shadow_material (node, node->background_texture);
+          node->background_shadow_material = _st_create_shadow_material (shadow_spec,
+                                                                         node->background_texture);
         }
     }
 
@@ -824,32 +649,6 @@ paint_texture_with_opacity (CoglHandle       texture,
 }
 
 static void
-paint_shadow_with_opacity (CoglHandle       shadow_material,
-                           StShadow        *shadow_spec,
-                           ClutterActorBox *box,
-                           guint8           paint_opacity)
-{
-  ClutterActorBox shadow_box;
-  CoglColor       color;
-
-  st_shadow_get_box (shadow_spec, box, &shadow_box);
-
-  cogl_color_set_from_4ub (&color,
-                           shadow_spec->color.red   * paint_opacity / 255,
-                           shadow_spec->color.green * paint_opacity / 255,
-                           shadow_spec->color.blue  * paint_opacity / 255,
-                           shadow_spec->color.alpha * paint_opacity / 255);
-  cogl_color_premultiply (&color);
-
-  cogl_material_set_layer_combine_constant (shadow_material, 0, &color);
-
-  cogl_set_source (shadow_material);
-  cogl_rectangle_with_texture_coords (shadow_box.x1, shadow_box.y1,
-                                      shadow_box.x2, shadow_box.y2,
-                                      0, 0, 1, 1);
-}
-
-static void
 st_theme_node_paint_borders (StThemeNode           *node,
                              const ClutterActorBox *box,
                              guint8                 paint_opacity)
@@ -1162,10 +961,10 @@ st_theme_node_paint (StThemeNode           *node,
    */
 
   if (node->border_shadow_material)
-    paint_shadow_with_opacity (node->border_shadow_material,
-                               node->shadow,
-                               &allocation,
-                               paint_opacity);
+    _st_paint_shadow_with_opacity (node->shadow,
+                                   node->border_shadow_material,
+                                   &allocation,
+                                   paint_opacity);
 
   if (node->border_texture != COGL_INVALID_HANDLE)
     {
@@ -1199,10 +998,10 @@ st_theme_node_paint (StThemeNode           *node,
        * like boder and background color into account).
        */
       if (node->background_shadow_material != COGL_INVALID_HANDLE)
-        paint_shadow_with_opacity (node->background_shadow_material,
-                                   node->shadow,
-                                   &background_box,
-                                   paint_opacity);
+        _st_paint_shadow_with_opacity (node->shadow,
+                                       node->background_shadow_material,
+                                       &background_box,
+                                       paint_opacity);
 
       paint_texture_with_opacity (node->background_texture, &background_box, paint_opacity);
     }



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