[gnome-shell] [StThemeNode] Make shadow helper functions semi-public
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] [StThemeNode] Make shadow helper functions semi-public
- Date: Thu, 2 Sep 2010 20:07:04 +0000 (UTC)
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]