now just uses meta_gradient_add_alpha (draw_op_as_pixbuf): implement alpha

2002-05-31  Havoc Pennington  <hp@redhat.com>

	* src/theme.c (multiply_alpha): now just uses
	meta_gradient_add_alpha
	(draw_op_as_pixbuf): implement alpha gradients for tint, gradient,
	and image draw ops, so I can implement garrett's stuff.

	* src/gradient.c (meta_gradient_add_alpha): new function to
	multiply the alpha channel of a pixbuf by an alpha gradient
This commit is contained in:
Havoc Pennington 2002-05-31 21:18:11 +00:00 committed by Havoc Pennington
parent 8da3b943a9
commit d4b91dc654
7 changed files with 504 additions and 101 deletions

View File

@ -1,3 +1,13 @@
2002-05-31 Havoc Pennington <hp@redhat.com>
* src/theme.c (multiply_alpha): now just uses
meta_gradient_add_alpha
(draw_op_as_pixbuf): implement alpha gradients for tint, gradient,
and image draw ops, so I can implement garrett's stuff.
* src/gradient.c (meta_gradient_add_alpha): new function to
multiply the alpha channel of a pixbuf by an alpha gradient
2002-05-30 Havoc Pennington <hp@redhat.com> 2002-05-30 Havoc Pennington <hp@redhat.com>
* src/main.c (main): verbose-log on startup whether we were * src/main.c (main): verbose-log on startup whether we were

View File

@ -730,3 +730,176 @@ meta_gradient_create_multi_diagonal (int width, int height,
return pixbuf; return pixbuf;
} }
static void
simple_multiply_alpha (GdkPixbuf *pixbuf,
guchar alpha)
{
guchar *pixels;
int rowstride;
int height;
int row;
g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
if (alpha == 255)
return;
g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
row = 0;
while (row < height)
{
guchar *p;
guchar *end;
p = pixels + row * rowstride;
end = p + rowstride;
while (p != end)
{
p += 3; /* skip RGB */
/* multiply the two alpha channels. not sure this is right.
* but some end cases are that if the pixbuf contains 255,
* then it should be modified to contain "alpha"; if the
* pixbuf contains 0, it should remain 0.
*/
/* ((*p / 255.0) * (alpha / 255.0)) * 255; */
*p = (guchar) (((int) *p * (int) alpha) / (int) 255);
++p; /* skip A */
}
++row;
}
}
static void
meta_gradient_add_alpha_horizontal (GdkPixbuf *pixbuf,
const unsigned char *alphas,
int n_alphas)
{
int i, j;
long a, da;
unsigned char *p;
unsigned char *pixels;
int width2;
int rowstride;
int width, height;
unsigned char *gradient;
unsigned char *gradient_p;
unsigned char *gradient_end;
g_return_if_fail (n_alphas > 0);
if (n_alphas == 1)
{
/* Optimize this */
simple_multiply_alpha (pixbuf, alphas[0]);
return;
}
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
gradient = g_new (unsigned char, width);
gradient_end = gradient + width;
if (n_alphas > width)
n_alphas = width;
if (n_alphas > 1)
width2 = width / (n_alphas - 1);
else
width2 = width;
a = alphas[0] << 8;
gradient_p = gradient;
/* render the gradient into an array */
for (i = 1; i < n_alphas; i++)
{
da = (((int)(alphas[i] - (int) alphas[i-1])) << 8) / (int) width2;
for (j = 0; j < width2; j++)
{
*gradient_p++ = (a >> 8);
a += da;
}
a = alphas[i] << 8;
}
/* get leftover pixels */
while (gradient_p != gradient_end)
{
*gradient_p++ = a >> 8;
}
/* Now for each line of the pixbuf, fill in with the gradient */
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
p = pixels;
i = 0;
while (i < height)
{
unsigned char *row_end = p + rowstride;
gradient_p = gradient;
p += 3;
while (gradient_p != gradient_end)
{
/* multiply the two alpha channels. not sure this is right.
* but some end cases are that if the pixbuf contains 255,
* then it should be modified to contain "alpha"; if the
* pixbuf contains 0, it should remain 0.
*/
/* ((*p / 255.0) * (alpha / 255.0)) * 255; */
*p = (guchar) (((int) *p * (int) *gradient_p) / (int) 255);
p += 4;
++gradient_p;
}
p = row_end;
++i;
}
g_free (gradient);
}
void
meta_gradient_add_alpha (GdkPixbuf *pixbuf,
const guchar *alphas,
int n_alphas,
MetaGradientType type)
{
g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
g_return_if_fail (gdk_pixbuf_get_has_alpha (pixbuf));
g_return_if_fail (n_alphas > 0);
switch (type)
{
case META_GRADIENT_HORIZONTAL:
meta_gradient_add_alpha_horizontal (pixbuf, alphas, n_alphas);
break;
case META_GRADIENT_VERTICAL:
g_printerr ("metacity: vertical alpha channel gradient not implemented yet\n");
break;
case META_GRADIENT_DIAGONAL:
g_printerr ("metacity: diagonal alpha channel gradient not implemented yet\n");
break;
case META_GRADIENT_LAST:
g_assert_not_reached ();
break;
}
}

View File

@ -51,4 +51,13 @@ GdkPixbuf* meta_gradient_create_interwoven (int width,
int thickness2); int thickness2);
/* Generate an alpha gradient and multiply it with the existing alpha
* channel of the given pixbuf
*/
void meta_gradient_add_alpha (GdkPixbuf *pixbuf,
const guchar *alphas,
int n_alphas,
MetaGradientType type);
#endif #endif

View File

@ -26,15 +26,82 @@ typedef void (* RenderGradientFunc) (GdkDrawable *drawable,
int width, int width,
int height); int height);
static void
draw_checkerboard (GdkDrawable *drawable,
int width,
int height)
{
gint i, j, xcount, ycount;
GdkGC *gc1, *gc2;
GdkColor color;
#define CHECK_SIZE 10
#define SPACING 2
/* It would be a bit more efficient to keep these
* GC's around instead of recreating on each expose, but
* this is the lazy/slow way.
*/
gc1 = gdk_gc_new (drawable);
color.red = 30000;
color.green = 30000;
color.blue = 30000;
gdk_gc_set_rgb_fg_color (gc1, &color);
gc2 = gdk_gc_new (drawable);
color.red = 50000;
color.green = 50000;
color.blue = 50000;
gdk_gc_set_rgb_fg_color (gc2, &color);
xcount = 0;
i = SPACING;
while (i < width)
{
j = SPACING;
ycount = xcount % 2; /* start with even/odd depending on row */
while (j < height)
{
GdkGC *gc;
if (ycount % 2)
gc = gc1;
else
gc = gc2;
/* If we're outside event->area, this will do nothing.
* It might be mildly more efficient if we handled
* the clipping ourselves, but again we're feeling lazy.
*/
gdk_draw_rectangle (drawable,
gc,
TRUE,
i, j,
CHECK_SIZE,
CHECK_SIZE);
j += CHECK_SIZE + SPACING;
++ycount;
}
i += CHECK_SIZE + SPACING;
++xcount;
}
g_object_unref (G_OBJECT (gc1));
g_object_unref (G_OBJECT (gc2));
}
static void static void
render_simple (GdkDrawable *drawable, render_simple (GdkDrawable *drawable,
GdkGC *gc, GdkGC *gc,
int width, int height, int width, int height,
MetaGradientType type) MetaGradientType type,
gboolean with_alpha)
{ {
GdkPixbuf *pixbuf; GdkPixbuf *pixbuf;
GdkColor from, to; GdkColor from, to;
gdk_color_parse ("blue", &from); gdk_color_parse ("blue", &from);
gdk_color_parse ("green", &to); gdk_color_parse ("green", &to);
@ -42,6 +109,26 @@ render_simple (GdkDrawable *drawable,
&from, &to, &from, &to,
type); type);
if (with_alpha)
{
const unsigned char alphas[] = { 0xff, 0xaa, 0x2f, 0x0, 0xcc, 0xff, 0xff };
if (!gdk_pixbuf_get_has_alpha (pixbuf))
{
GdkPixbuf *new_pixbuf;
new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
g_object_unref (G_OBJECT (pixbuf));
pixbuf = new_pixbuf;
}
meta_gradient_add_alpha (pixbuf,
alphas, G_N_ELEMENTS (alphas),
META_GRADIENT_HORIZONTAL);
draw_checkerboard (drawable, width, height);
}
gdk_pixbuf_render_to_drawable (pixbuf, gdk_pixbuf_render_to_drawable (pixbuf,
drawable, drawable,
gc, gc,
@ -58,7 +145,7 @@ render_vertical_func (GdkDrawable *drawable,
GdkGC *gc, GdkGC *gc,
int width, int height) int width, int height)
{ {
render_simple (drawable, gc, width, height, META_GRADIENT_VERTICAL); render_simple (drawable, gc, width, height, META_GRADIENT_VERTICAL, FALSE);
} }
static void static void
@ -66,7 +153,7 @@ render_horizontal_func (GdkDrawable *drawable,
GdkGC *gc, GdkGC *gc,
int width, int height) int width, int height)
{ {
render_simple (drawable, gc, width, height, META_GRADIENT_HORIZONTAL); render_simple (drawable, gc, width, height, META_GRADIENT_HORIZONTAL, FALSE);
} }
static void static void
@ -74,7 +161,15 @@ render_diagonal_func (GdkDrawable *drawable,
GdkGC *gc, GdkGC *gc,
int width, int height) int width, int height)
{ {
render_simple (drawable, gc, width, height, META_GRADIENT_DIAGONAL); render_simple (drawable, gc, width, height, META_GRADIENT_DIAGONAL, FALSE);
}
static void
render_diagonal_alpha_func (GdkDrawable *drawable,
GdkGC *gc,
int width, int height)
{
render_simple (drawable, gc, width, height, META_GRADIENT_DIAGONAL, TRUE);
} }
static void static void
@ -230,6 +325,10 @@ meta_gradient_test (void)
window = create_gradient_window ("Interwoven", window = create_gradient_window ("Interwoven",
render_interwoven_func); render_interwoven_func);
window = create_gradient_window ("Simple diagonal with horizontal multi alpha",
render_diagonal_alpha_func);
} }
int int

View File

@ -577,22 +577,81 @@ parse_angle (const char *str,
} }
static gboolean static gboolean
parse_alpha (const char *str, parse_alpha (const char *str,
double *val, MetaAlphaGradientSpec **spec_ret,
GMarkupParseContext *context, GMarkupParseContext *context,
GError **error) GError **error)
{ {
if (!parse_double (str, val, context, error)) char **split;
return FALSE; int i;
int n_alphas;
MetaAlphaGradientSpec *spec;
if (*val < (0.0 - 1e6) || *val > (1.0 + 1e6)) *spec_ret = NULL;
split = g_strsplit (str, ":", -1);
i = 0;
while (split[i])
++i;
if (i == 0)
{ {
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Alpha must be between 0.0 (invisible) and 1.0 (fully opaque), was %g\n"), _("Could not parse \"%s\" as a floating point number"),
*val); str);
g_strfreev (split);
return FALSE; return FALSE;
} }
n_alphas = i;
/* FIXME allow specifying horizontal/vertical/diagonal in theme format,
* once we implement vertical/diagonal in gradient.c
*/
spec = meta_alpha_gradient_spec_new (META_GRADIENT_HORIZONTAL,
n_alphas);
i = 0;
while (i < n_alphas)
{
double v;
if (!parse_double (split[i], &v, context, error))
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Could not parse \"%s\" as a floating point number"),
split[i]);
g_strfreev (split);
meta_alpha_gradient_spec_free (spec);
return FALSE;
}
if (v < (0.0 - 1e6) || v > (1.0 + 1e6))
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Alpha must be between 0.0 (invisible) and 1.0 (fully opaque), was %g\n"),
v);
g_strfreev (split);
meta_alpha_gradient_spec_free (spec);
return FALSE;
}
spec->alphas[i] = (unsigned char) (v * 255);
++i;
}
g_strfreev (split);
*spec_ret = spec;
return TRUE; return TRUE;
} }
@ -1886,7 +1945,7 @@ parse_draw_op_element (GMarkupParseContext *context,
const char *width; const char *width;
const char *height; const char *height;
const char *alpha; const char *alpha;
double alpha_val; MetaAlphaGradientSpec *alpha_spec;
MetaColorSpec *color_spec; MetaColorSpec *color_spec;
if (!locate_attributes (context, element_name, attribute_names, attribute_values, if (!locate_attributes (context, element_name, attribute_names, attribute_values,
@ -1952,7 +2011,8 @@ parse_draw_op_element (GMarkupParseContext *context,
if (!check_expression (height, FALSE, info->theme, context, error)) if (!check_expression (height, FALSE, info->theme, context, error))
return; return;
if (!parse_alpha (alpha, &alpha_val, context, error)) alpha_spec = NULL;
if (!parse_alpha (alpha, &alpha_spec, context, error))
return; return;
/* Check last so we don't have to free it when other /* Check last so we don't have to free it when other
@ -1961,6 +2021,9 @@ parse_draw_op_element (GMarkupParseContext *context,
color_spec = meta_color_spec_new_from_string (color, error); color_spec = meta_color_spec_new_from_string (color, error);
if (color_spec == NULL) if (color_spec == NULL)
{ {
if (alpha_spec)
meta_alpha_gradient_spec_free (alpha_spec);
add_context_to_error (error, context); add_context_to_error (error, context);
return; return;
} }
@ -1968,11 +2031,11 @@ parse_draw_op_element (GMarkupParseContext *context,
op = meta_draw_op_new (META_DRAW_TINT); op = meta_draw_op_new (META_DRAW_TINT);
op->data.tint.color_spec = color_spec; op->data.tint.color_spec = color_spec;
op->data.tint.alpha_spec = alpha_spec;
op->data.tint.x = optimize_expression (info->theme, x); op->data.tint.x = optimize_expression (info->theme, x);
op->data.tint.y = optimize_expression (info->theme, y); op->data.tint.y = optimize_expression (info->theme, y);
op->data.tint.width = optimize_expression (info->theme, width); op->data.tint.width = optimize_expression (info->theme, width);
op->data.tint.height = optimize_expression (info->theme, height); op->data.tint.height = optimize_expression (info->theme, height);
op->data.tint.alpha = alpha_val;
g_assert (info->op_list); g_assert (info->op_list);
@ -1988,7 +2051,7 @@ parse_draw_op_element (GMarkupParseContext *context,
const char *height; const char *height;
const char *type; const char *type;
const char *alpha; const char *alpha;
double alpha_val; MetaAlphaGradientSpec *alpha_spec;
MetaGradientType type_val; MetaGradientType type_val;
if (!locate_attributes (context, element_name, attribute_names, attribute_values, if (!locate_attributes (context, element_name, attribute_names, attribute_values,
@ -2046,10 +2109,6 @@ parse_draw_op_element (GMarkupParseContext *context,
if (!check_expression (height, FALSE, info->theme, context, error)) if (!check_expression (height, FALSE, info->theme, context, error))
return; return;
alpha_val = 1.0;
if (alpha && !parse_alpha (alpha, &alpha_val, context, error))
return;
type_val = meta_gradient_type_from_string (type); type_val = meta_gradient_type_from_string (type);
if (type_val == META_GRADIENT_LAST) if (type_val == META_GRADIENT_LAST)
@ -2060,6 +2119,10 @@ parse_draw_op_element (GMarkupParseContext *context,
return; return;
} }
alpha_spec = NULL;
if (alpha && !parse_alpha (alpha, &alpha_spec, context, error))
return;
g_assert (info->op == NULL); g_assert (info->op == NULL);
info->op = meta_draw_op_new (META_DRAW_GRADIENT); info->op = meta_draw_op_new (META_DRAW_GRADIENT);
@ -2068,10 +2131,9 @@ parse_draw_op_element (GMarkupParseContext *context,
info->op->data.gradient.width = optimize_expression (info->theme, width); info->op->data.gradient.width = optimize_expression (info->theme, width);
info->op->data.gradient.height = optimize_expression (info->theme, height); info->op->data.gradient.height = optimize_expression (info->theme, height);
info->op->data.gradient.gradient_spec = info->op->data.gradient.gradient_spec = meta_gradient_spec_new (type_val);
meta_gradient_spec_new (type_val);
info->op->data.gradient.alpha = alpha_val; info->op->data.gradient.alpha_spec = alpha_spec;
push_state (info, STATE_GRADIENT); push_state (info, STATE_GRADIENT);
@ -2087,7 +2149,7 @@ parse_draw_op_element (GMarkupParseContext *context,
const char *height; const char *height;
const char *alpha; const char *alpha;
const char *colorize; const char *colorize;
double alpha_val; MetaAlphaGradientSpec *alpha_spec;
GdkPixbuf *pixbuf; GdkPixbuf *pixbuf;
MetaColorSpec *colorize_spec = NULL; MetaColorSpec *colorize_spec = NULL;
@ -2147,9 +2209,6 @@ parse_draw_op_element (GMarkupParseContext *context,
if (!check_expression (height, TRUE, info->theme, context, error)) if (!check_expression (height, TRUE, info->theme, context, error))
return; return;
alpha_val = 1.0;
if (alpha && !parse_alpha (alpha, &alpha_val, context, error))
return;
/* Check last so we don't have to free it when other /* Check last so we don't have to free it when other
* stuff fails * stuff fails
@ -2173,6 +2232,13 @@ parse_draw_op_element (GMarkupParseContext *context,
return; return;
} }
} }
alpha_spec = NULL;
if (alpha && !parse_alpha (alpha, &alpha_spec, context, error))
{
g_object_unref (G_OBJECT (pixbuf));
return;
}
op = meta_draw_op_new (META_DRAW_IMAGE); op = meta_draw_op_new (META_DRAW_IMAGE);
@ -2182,7 +2248,7 @@ parse_draw_op_element (GMarkupParseContext *context,
op->data.image.y = optimize_expression (info->theme, y); op->data.image.y = optimize_expression (info->theme, y);
op->data.image.width = optimize_expression (info->theme, width); op->data.image.width = optimize_expression (info->theme, width);
op->data.image.height = optimize_expression (info->theme, height); op->data.image.height = optimize_expression (info->theme, height);
op->data.image.alpha = alpha_val; op->data.image.alpha_spec = alpha_spec;
g_assert (info->op_list); g_assert (info->op_list);
@ -2523,7 +2589,7 @@ parse_draw_op_element (GMarkupParseContext *context,
const char *width; const char *width;
const char *height; const char *height;
const char *alpha; const char *alpha;
double alpha_val; MetaAlphaGradientSpec *alpha_spec;
if (!locate_attributes (context, element_name, attribute_names, attribute_values, if (!locate_attributes (context, element_name, attribute_names, attribute_values,
error, error,
@ -2573,8 +2639,8 @@ parse_draw_op_element (GMarkupParseContext *context,
if (!check_expression (height, FALSE, info->theme, context, error)) if (!check_expression (height, FALSE, info->theme, context, error))
return; return;
alpha_val = 1.0; alpha_spec = NULL;
if (alpha && !parse_alpha (alpha, &alpha_val, context, error)) if (alpha && !parse_alpha (alpha, &alpha_spec, context, error))
return; return;
op = meta_draw_op_new (META_DRAW_ICON); op = meta_draw_op_new (META_DRAW_ICON);
@ -2583,7 +2649,7 @@ parse_draw_op_element (GMarkupParseContext *context,
op->data.icon.y = optimize_expression (info->theme, y); op->data.icon.y = optimize_expression (info->theme, y);
op->data.icon.width = optimize_expression (info->theme, width); op->data.icon.width = optimize_expression (info->theme, width);
op->data.icon.height = optimize_expression (info->theme, height); op->data.icon.height = optimize_expression (info->theme, height);
op->data.icon.alpha = alpha_val; op->data.icon.alpha_spec = alpha_spec;
g_assert (info->op_list); g_assert (info->op_list);

View File

@ -753,6 +753,32 @@ meta_gradient_spec_validate (MetaGradientSpec *spec,
return TRUE; return TRUE;
} }
MetaAlphaGradientSpec*
meta_alpha_gradient_spec_new (MetaGradientType type,
int n_alphas)
{
MetaAlphaGradientSpec *spec;
g_return_val_if_fail (n_alphas > 0, NULL);
spec = g_new0 (MetaAlphaGradientSpec, 1);
spec->type = type;
spec->alphas = g_new0 (unsigned char, n_alphas);
spec->n_alphas = n_alphas;
return spec;
}
void
meta_alpha_gradient_spec_free (MetaAlphaGradientSpec *spec)
{
g_return_if_fail (spec != NULL);
g_free (spec->alphas);
g_free (spec);
}
MetaColorSpec* MetaColorSpec*
meta_color_spec_new (MetaColorSpecType type) meta_color_spec_new (MetaColorSpecType type)
{ {
@ -2347,6 +2373,8 @@ meta_draw_op_free (MetaDrawOp *op)
case META_DRAW_TINT: case META_DRAW_TINT:
if (op->data.tint.color_spec) if (op->data.tint.color_spec)
meta_color_spec_free (op->data.tint.color_spec); meta_color_spec_free (op->data.tint.color_spec);
if (op->data.tint.alpha_spec)
meta_alpha_gradient_spec_free (op->data.tint.alpha_spec);
g_free (op->data.tint.x); g_free (op->data.tint.x);
g_free (op->data.tint.y); g_free (op->data.tint.y);
g_free (op->data.tint.width); g_free (op->data.tint.width);
@ -2356,6 +2384,8 @@ meta_draw_op_free (MetaDrawOp *op)
case META_DRAW_GRADIENT: case META_DRAW_GRADIENT:
if (op->data.gradient.gradient_spec) if (op->data.gradient.gradient_spec)
meta_gradient_spec_free (op->data.gradient.gradient_spec); meta_gradient_spec_free (op->data.gradient.gradient_spec);
if (op->data.gradient.alpha_spec)
meta_alpha_gradient_spec_free (op->data.gradient.alpha_spec);
g_free (op->data.gradient.x); g_free (op->data.gradient.x);
g_free (op->data.gradient.y); g_free (op->data.gradient.y);
g_free (op->data.gradient.width); g_free (op->data.gradient.width);
@ -2363,6 +2393,8 @@ meta_draw_op_free (MetaDrawOp *op)
break; break;
case META_DRAW_IMAGE: case META_DRAW_IMAGE:
if (op->data.image.alpha_spec)
meta_alpha_gradient_spec_free (op->data.image.alpha_spec);
if (op->data.image.pixbuf) if (op->data.image.pixbuf)
g_object_unref (G_OBJECT (op->data.image.pixbuf)); g_object_unref (G_OBJECT (op->data.image.pixbuf));
if (op->data.image.colorize_spec) if (op->data.image.colorize_spec)
@ -2375,7 +2407,6 @@ meta_draw_op_free (MetaDrawOp *op)
g_free (op->data.image.height); g_free (op->data.image.height);
break; break;
case META_DRAW_GTK_ARROW: case META_DRAW_GTK_ARROW:
g_free (op->data.gtk_arrow.x); g_free (op->data.gtk_arrow.x);
g_free (op->data.gtk_arrow.y); g_free (op->data.gtk_arrow.y);
@ -2397,6 +2428,8 @@ meta_draw_op_free (MetaDrawOp *op)
break; break;
case META_DRAW_ICON: case META_DRAW_ICON:
if (op->data.icon.alpha_spec)
meta_alpha_gradient_spec_free (op->data.icon.alpha_spec);
g_free (op->data.icon.x); g_free (op->data.icon.x);
g_free (op->data.icon.y); g_free (op->data.icon.y);
g_free (op->data.icon.width); g_free (op->data.icon.width);
@ -2464,21 +2497,21 @@ get_gc_for_primitive (GtkWidget *widget,
} }
static GdkPixbuf* static GdkPixbuf*
multiply_alpha (GdkPixbuf *pixbuf, apply_alpha (GdkPixbuf *pixbuf,
guchar alpha, MetaAlphaGradientSpec *spec,
gboolean force_copy) gboolean force_copy)
{ {
GdkPixbuf *new_pixbuf; GdkPixbuf *new_pixbuf;
guchar *pixels; gboolean needs_alpha;
int rowstride;
int height;
int row;
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL); g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
if (alpha == 255) needs_alpha = spec && (spec->n_alphas > 1 ||
return pixbuf; spec->alphas[0] != 0xff);
if (!needs_alpha)
return pixbuf;
if (!gdk_pixbuf_get_has_alpha (pixbuf)) if (!gdk_pixbuf_get_has_alpha (pixbuf))
{ {
new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0); new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
@ -2493,38 +2526,9 @@ multiply_alpha (GdkPixbuf *pixbuf,
} }
g_assert (gdk_pixbuf_get_has_alpha (pixbuf)); g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
meta_gradient_add_alpha (pixbuf, spec->alphas, spec->n_alphas, spec->type);
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
row = 0;
while (row < height)
{
guchar *p;
guchar *end;
p = pixels + row * rowstride;
end = p + rowstride;
while (p != end)
{
p += 3; /* skip RGB */
/* multiply the two alpha channels. not sure this is right.
* but some end cases are that if the pixbuf contains 255,
* then it should be modified to contain "alpha"; if the
* pixbuf contains 0, it should remain 0.
*/
/* ((*p / 255.0) * (alpha / 255.0)) * 255; */
*p = (guchar) (((int) *p * (int) alpha) / (int) 255);
++p; /* skip A */
}
++row;
}
return pixbuf; return pixbuf;
} }
@ -2578,10 +2582,10 @@ render_pixbuf (GdkDrawable *drawable,
} }
static GdkPixbuf* static GdkPixbuf*
scale_and_alpha_pixbuf (GdkPixbuf *src, scale_and_alpha_pixbuf (GdkPixbuf *src,
double alpha, MetaAlphaGradientSpec *alpha_spec,
int width, int width,
int height) int height)
{ {
GdkPixbuf *pixbuf; GdkPixbuf *pixbuf;
@ -2611,9 +2615,7 @@ scale_and_alpha_pixbuf (GdkPixbuf *src,
} }
if (pixbuf) if (pixbuf)
pixbuf = multiply_alpha (pixbuf, pixbuf = apply_alpha (pixbuf, alpha_spec, pixbuf == src);
ALPHA_TO_UCHAR (alpha),
pixbuf == src);
return pixbuf; return pixbuf;
} }
@ -2665,20 +2667,46 @@ draw_op_as_pixbuf (const MetaDrawOp *op,
{ {
GdkColor color; GdkColor color;
guint32 rgba; guint32 rgba;
gboolean has_alpha;
meta_color_spec_render (op->data.rectangle.color_spec, meta_color_spec_render (op->data.rectangle.color_spec,
widget, widget,
&color); &color);
has_alpha =
op->data.tint.alpha_spec &&
(op->data.tint.alpha_spec->n_alphas > 1 ||
op->data.tint.alpha_spec->alphas[0] != 0xff);
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
ALPHA_TO_UCHAR (op->data.tint.alpha) < 255, has_alpha,
8, width, height); 8, width, height);
rgba = GDK_COLOR_RGBA (color); if (!has_alpha)
rgba &= ~0xff; {
rgba |= ALPHA_TO_UCHAR (op->data.tint.alpha); rgba = GDK_COLOR_RGBA (color);
gdk_pixbuf_fill (pixbuf, rgba);
}
else if (op->data.tint.alpha_spec->n_alphas == 1)
{
rgba = GDK_COLOR_RGBA (color);
rgba &= ~0xff;
rgba |= op->data.tint.alpha_spec->alphas[0];
gdk_pixbuf_fill (pixbuf, rgba);
}
else
{
rgba = GDK_COLOR_RGBA (color);
gdk_pixbuf_fill (pixbuf, rgba);
gdk_pixbuf_fill (pixbuf, rgba); meta_gradient_add_alpha (pixbuf,
op->data.tint.alpha_spec->alphas,
op->data.tint.alpha_spec->n_alphas,
op->data.tint.alpha_spec->type);
}
} }
break; break;
@ -2687,9 +2715,9 @@ draw_op_as_pixbuf (const MetaDrawOp *op,
pixbuf = meta_gradient_spec_render (op->data.gradient.gradient_spec, pixbuf = meta_gradient_spec_render (op->data.gradient.gradient_spec,
widget, width, height); widget, width, height);
pixbuf = multiply_alpha (pixbuf, pixbuf = apply_alpha (pixbuf,
ALPHA_TO_UCHAR (op->data.gradient.alpha), op->data.gradient.alpha_spec,
FALSE); FALSE);
} }
break; break;
@ -2720,17 +2748,17 @@ draw_op_as_pixbuf (const MetaDrawOp *op,
if (op->data.image.colorize_cache_pixbuf) if (op->data.image.colorize_cache_pixbuf)
{ {
pixbuf = scale_and_alpha_pixbuf (op->data.image.colorize_cache_pixbuf, pixbuf = scale_and_alpha_pixbuf (op->data.image.colorize_cache_pixbuf,
op->data.image.alpha, op->data.image.alpha_spec,
width, height); width, height);
} }
} }
else else
{ {
pixbuf = scale_and_alpha_pixbuf (op->data.image.pixbuf, pixbuf = scale_and_alpha_pixbuf (op->data.image.pixbuf,
op->data.image.alpha, op->data.image.alpha_spec,
width, height); width, height);
} }
break; break;
} }
case META_DRAW_GTK_ARROW: case META_DRAW_GTK_ARROW:
@ -2743,11 +2771,11 @@ draw_op_as_pixbuf (const MetaDrawOp *op,
width <= gdk_pixbuf_get_width (info->mini_icon) && width <= gdk_pixbuf_get_width (info->mini_icon) &&
height <= gdk_pixbuf_get_height (info->mini_icon)) height <= gdk_pixbuf_get_height (info->mini_icon))
pixbuf = scale_and_alpha_pixbuf (info->mini_icon, pixbuf = scale_and_alpha_pixbuf (info->mini_icon,
op->data.icon.alpha, op->data.icon.alpha_spec,
width, height); width, height);
else if (info->icon) else if (info->icon)
pixbuf = scale_and_alpha_pixbuf (info->icon, pixbuf = scale_and_alpha_pixbuf (info->icon,
op->data.icon.alpha, op->data.icon.alpha_spec,
width, height); width, height);
break; break;
@ -2902,13 +2930,18 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
case META_DRAW_TINT: case META_DRAW_TINT:
{ {
int rx, ry, rwidth, rheight; int rx, ry, rwidth, rheight;
gboolean needs_alpha;
needs_alpha = op->data.tint.alpha_spec &&
(op->data.tint.alpha_spec->n_alphas > 1 ||
op->data.tint.alpha_spec->alphas[0] != 0xff);
rx = parse_x_position_unchecked (op->data.tint.x, env); rx = parse_x_position_unchecked (op->data.tint.x, env);
ry = parse_y_position_unchecked (op->data.tint.y, env); ry = parse_y_position_unchecked (op->data.tint.y, env);
rwidth = parse_size_unchecked (op->data.tint.width, env); rwidth = parse_size_unchecked (op->data.tint.width, env);
rheight = parse_size_unchecked (op->data.tint.height, env); rheight = parse_size_unchecked (op->data.tint.height, env);
if (ALPHA_TO_UCHAR (op->data.tint.alpha) == 255) if (!needs_alpha)
{ {
gc = get_gc_for_primitive (widget, drawable, gc = get_gc_for_primitive (widget, drawable,
op->data.tint.color_spec, op->data.tint.color_spec,

View File

@ -31,6 +31,7 @@ typedef struct _MetaFrameStyleSet MetaFrameStyleSet;
typedef struct _MetaDrawOp MetaDrawOp; typedef struct _MetaDrawOp MetaDrawOp;
typedef struct _MetaDrawOpList MetaDrawOpList; typedef struct _MetaDrawOpList MetaDrawOpList;
typedef struct _MetaGradientSpec MetaGradientSpec; typedef struct _MetaGradientSpec MetaGradientSpec;
typedef struct _MetaAlphaGradientSpec MetaAlphaGradientSpec;
typedef struct _MetaColorSpec MetaColorSpec; typedef struct _MetaColorSpec MetaColorSpec;
typedef struct _MetaFrameLayout MetaFrameLayout; typedef struct _MetaFrameLayout MetaFrameLayout;
typedef struct _MetaFrameGeometry MetaFrameGeometry; typedef struct _MetaFrameGeometry MetaFrameGeometry;
@ -169,6 +170,13 @@ struct _MetaGradientSpec
GSList *color_specs; GSList *color_specs;
}; };
struct _MetaAlphaGradientSpec
{
MetaGradientType type;
unsigned char *alphas;
int n_alphas;
};
struct _MetaDrawInfo struct _MetaDrawInfo
{ {
GdkPixbuf *mini_icon; GdkPixbuf *mini_icon;
@ -256,7 +264,7 @@ struct _MetaDrawOp
struct { struct {
MetaColorSpec *color_spec; MetaColorSpec *color_spec;
double alpha; MetaAlphaGradientSpec *alpha_spec;
char *x; char *x;
char *y; char *y;
char *width; char *width;
@ -265,7 +273,7 @@ struct _MetaDrawOp
struct { struct {
MetaGradientSpec *gradient_spec; MetaGradientSpec *gradient_spec;
double alpha; MetaAlphaGradientSpec *alpha_spec;
char *x; char *x;
char *y; char *y;
char *width; char *width;
@ -274,6 +282,7 @@ struct _MetaDrawOp
struct { struct {
MetaColorSpec *colorize_spec; MetaColorSpec *colorize_spec;
MetaAlphaGradientSpec *alpha_spec;
GdkPixbuf *pixbuf; GdkPixbuf *pixbuf;
double alpha; double alpha;
char *x; char *x;
@ -312,7 +321,7 @@ struct _MetaDrawOp
} gtk_vline; } gtk_vline;
struct { struct {
double alpha; MetaAlphaGradientSpec *alpha_spec;
char *x; char *x;
char *y; char *y;
char *width; char *width;
@ -618,6 +627,10 @@ GdkPixbuf* meta_gradient_spec_render (const MetaGradientSpec *desc,
gboolean meta_gradient_spec_validate (MetaGradientSpec *spec, gboolean meta_gradient_spec_validate (MetaGradientSpec *spec,
GError **error); GError **error);
MetaAlphaGradientSpec* meta_alpha_gradient_spec_new (MetaGradientType type,
int n_alphas);
void meta_alpha_gradient_spec_free (MetaAlphaGradientSpec *spec);
MetaFrameStyle* meta_frame_style_new (MetaFrameStyle *parent); MetaFrameStyle* meta_frame_style_new (MetaFrameStyle *parent);
void meta_frame_style_ref (MetaFrameStyle *style); void meta_frame_style_ref (MetaFrameStyle *style);