diff --git a/ChangeLog b/ChangeLog index 83b563f9f..8aec4a415 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2002-11-04 Havoc Pennington + + Patch from Brian Cameron to implement the vertical/horizontal + striped image accelerated scaling from the gtk pixbuf engine. + + * src/theme.c (scale_and_alpha_pixbuf): if an image is + vertical/horizontal stripes, use special extra-fast scaling + routines. + + * src/theme-parser.c (parse_draw_op_element): when loading an + image, mark it as vertically/horizontally striped when appropriate + 2002-11-04 Erwann Chenede - * src/xprops.c (meta_prop_get_values): changed __FUNCTION__ diff --git a/src/theme-parser.c b/src/theme-parser.c index 54ffe2752..88e95f3df 100644 --- a/src/theme-parser.c +++ b/src/theme-parser.c @@ -2246,6 +2246,9 @@ parse_draw_op_element (GMarkupParseContext *context, GdkPixbuf *pixbuf; MetaColorSpec *colorize_spec = NULL; MetaImageFillType fill_type_val; + int h, w, c; + int pixbuf_width, pixbuf_height, pixbuf_n_channels, pixbuf_rowstride; + guchar *pixbuf_pixels; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, @@ -2308,7 +2311,7 @@ parse_draw_op_element (GMarkupParseContext *context, if (fill_type) { fill_type_val = meta_image_fill_type_from_string (fill_type); - + if (((int) fill_type_val) == -1) { set_error (error, context, G_MARKUP_ERROR, @@ -2330,16 +2333,16 @@ parse_draw_op_element (GMarkupParseContext *context, } if (colorize) - { - colorize_spec = meta_color_spec_new_from_string (colorize, error); - - if (colorize_spec == NULL) - { - add_context_to_error (error, context); + { + colorize_spec = meta_color_spec_new_from_string (colorize, error); + + if (colorize_spec == NULL) + { + add_context_to_error (error, context); g_object_unref (G_OBJECT (pixbuf)); - return; - } - } + return; + } + } alpha_spec = NULL; if (alpha && !parse_alpha (alpha, &alpha_spec, context, error)) @@ -2359,6 +2362,67 @@ parse_draw_op_element (GMarkupParseContext *context, op->data.image.alpha_spec = alpha_spec; op->data.image.fill_type = fill_type_val; + /* Check for vertical & horizontal stripes */ + pixbuf_n_channels = gdk_pixbuf_get_n_channels(pixbuf); + pixbuf_width = gdk_pixbuf_get_width(pixbuf); + pixbuf_height = gdk_pixbuf_get_height(pixbuf); + pixbuf_rowstride = gdk_pixbuf_get_rowstride(pixbuf); + pixbuf_pixels = gdk_pixbuf_get_pixels(pixbuf); + + /* Check for horizontal stripes */ + for (h = 0; h < pixbuf_height; h++) + { + for (w = 1; w < pixbuf_width; w++) + { + for (c = 0; c < pixbuf_n_channels; c++) + { + if (pixbuf_pixels[(h * pixbuf_rowstride) + c] != + pixbuf_pixels[(h * pixbuf_rowstride) + w + c]) + break; + } + if (c < pixbuf_n_channels) + break; + } + if (w < pixbuf_width) + break; + } + + if (h >= pixbuf_height) + { + op->data.image.horizontal_stripes = TRUE; + } + else + { + op->data.image.horizontal_stripes = FALSE; + } + + /* Check for vertical stripes */ + for (w = 0; w < pixbuf_width; w++) + { + for (h = 1; h < pixbuf_height; h++) + { + for (c = 0; c < pixbuf_n_channels; c++) + { + if (pixbuf_pixels[w + c] != + pixbuf_pixels[(h * pixbuf_rowstride) + w + c]) + break; + } + if (c < pixbuf_n_channels) + break; + } + if (h < pixbuf_height) + break; + } + + if (w >= pixbuf_width) + { + op->data.image.vertical_stripes = TRUE; + } + else + { + op->data.image.vertical_stripes = FALSE; + } + g_assert (info->op_list); meta_draw_op_list_append (info->op_list, op); diff --git a/src/theme.c b/src/theme.c index 6f250904d..8ab23dee7 100644 --- a/src/theme.c +++ b/src/theme.c @@ -2804,18 +2804,107 @@ pixbuf_tile (GdkPixbuf *tile, return pixbuf; } +static GdkPixbuf * +replicate_rows (GdkPixbuf *src, + int src_x, + int src_y, + int width, + int height) +{ + unsigned int n_channels = gdk_pixbuf_get_n_channels (src); + unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src); + unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x + * n_channels); + unsigned char *dest_pixels; + GdkPixbuf *result; + unsigned int dest_rowstride; + int i; + + result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8, + width, height); + dest_rowstride = gdk_pixbuf_get_rowstride (result); + dest_pixels = gdk_pixbuf_get_pixels (result); + + for (i = 0; i < height; i++) + memcpy (dest_pixels + dest_rowstride * i, pixels, n_channels * width); + + return result; +} + +static GdkPixbuf * +replicate_cols (GdkPixbuf *src, + int src_x, + int src_y, + int width, + int height) +{ + unsigned int n_channels = gdk_pixbuf_get_n_channels (src); + unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src); + unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x + * n_channels); + unsigned char *dest_pixels; + GdkPixbuf *result; + unsigned int dest_rowstride; + int i, j; + + result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8, + width, height); + dest_rowstride = gdk_pixbuf_get_rowstride (result); + dest_pixels = gdk_pixbuf_get_pixels (result); + + for (i = 0; i < height; i++) + { + unsigned char *p = dest_pixels + dest_rowstride * i; + unsigned char *q = pixels + src_rowstride * i; + + unsigned char r = *(q++); + unsigned char g = *(q++); + unsigned char b = *(q++); + + if (n_channels == 4) + { + unsigned char a; + + a = *(q++); + + for (j = 0; j < width; j++) + { + *(p++) = r; + *(p++) = g; + *(p++) = b; + *(p++) = a; + } + } + else + { + for (j = 0; j < width; j++) + { + *(p++) = r; + *(p++) = g; + *(p++) = b; + } + } + } + + return result; +} + static GdkPixbuf* scale_and_alpha_pixbuf (GdkPixbuf *src, MetaAlphaGradientSpec *alpha_spec, MetaImageFillType fill_type, int width, - int height) + int height, + gboolean vertical_stripes, + gboolean horizontal_stripes) { GdkPixbuf *pixbuf; + GdkPixbuf *temp_pixbuf; pixbuf = NULL; pixbuf = src; + if (gdk_pixbuf_get_width (pixbuf) == width && gdk_pixbuf_get_height (pixbuf) == height) { @@ -2823,16 +2912,61 @@ scale_and_alpha_pixbuf (GdkPixbuf *src, } else { - switch (fill_type) + if (fill_type == META_IMAGE_FILL_TILE) { - case META_IMAGE_FILL_SCALE: - pixbuf = gdk_pixbuf_scale_simple (pixbuf, - width, height, - GDK_INTERP_BILINEAR); - break; - case META_IMAGE_FILL_TILE: pixbuf = pixbuf_tile (pixbuf, width, height); - break; + } + else + { + int src_h, src_w, dest_h, dest_w, pixbuf_width, pixbuf_height; + src_h = gdk_pixbuf_get_height (src); + src_w = gdk_pixbuf_get_width (src); + + if (vertical_stripes) + { + dest_w = width; + dest_h = gdk_pixbuf_get_height (src); + } + else if (horizontal_stripes) + { + dest_w = gdk_pixbuf_get_width (src); + dest_h = height; + } + else + { + dest_w = width; + dest_h = height; + } + + if (dest_w == src_w && dest_h == src_h) + { + temp_pixbuf = src; + g_object_ref (G_OBJECT (tmp_pixbuf)); + } + else + { + temp_pixbuf = gdk_pixbuf_scale_simple (src, + dest_w, dest_h, + GDK_INTERP_BILINEAR); + } + + /* prefer to replicate_cols if possible, as that + * is faster (no memory reads) + */ + if (horizontal_stripes) + { + pixbuf = replicate_cols (temp_pixbuf, 0, 0, width, height); + g_object_unref (G_OBJECT (temp_pixbuf)); + } + else if (vertical_stripes) + { + pixbuf = replicate_rows (temp_pixbuf, 0, 0, width, height); + g_object_unref (G_OBJECT (temp_pixbuf)); + } + else + { + pixbuf = temp_pixbuf; + } } } @@ -2972,15 +3106,19 @@ draw_op_as_pixbuf (const MetaDrawOp *op, pixbuf = scale_and_alpha_pixbuf (op->data.image.colorize_cache_pixbuf, op->data.image.alpha_spec, op->data.image.fill_type, - width, height); + width, height, + op->data.image.vertical_stripes, + op->data.image.horizontal_stripes); } } else { pixbuf = scale_and_alpha_pixbuf (op->data.image.pixbuf, - op->data.image.alpha_spec, + op->data.image.alpha_spec, op->data.image.fill_type, - width, height); + width, height, + op->data.image.vertical_stripes, + op->data.image.horizontal_stripes); } break; } @@ -2997,12 +3135,16 @@ draw_op_as_pixbuf (const MetaDrawOp *op, pixbuf = scale_and_alpha_pixbuf (info->mini_icon, op->data.icon.alpha_spec, op->data.icon.fill_type, - width, height); + width, height, + op->data.image.vertical_stripes, + op->data.image.horizontal_stripes); else if (info->icon) pixbuf = scale_and_alpha_pixbuf (info->icon, op->data.icon.alpha_spec, op->data.icon.fill_type, - width, height); + width, height, + op->data.image.vertical_stripes, + op->data.image.horizontal_stripes); break; case META_DRAW_TITLE: diff --git a/src/theme.h b/src/theme.h index 806edc373..f87e857d7 100644 --- a/src/theme.h +++ b/src/theme.h @@ -325,6 +325,8 @@ struct _MetaDrawOp guint32 colorize_cache_pixel; GdkPixbuf *colorize_cache_pixbuf; MetaImageFillType fill_type; + unsigned int vertical_stripes : 1; + unsigned int horizontal_stripes : 1; } image; struct {