diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2013-01-08 12:19:33 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2013-01-08 15:01:37 +0000 |
commit | 146da77d85b304651949a819bc8b0a74819f0416 (patch) | |
tree | 85f5a9f199ef491782045935d39ff93dae1a40e6 | |
parent | 5f2e89660d5e38d8e2682945962521958f150825 (diff) | |
download | cairo-146da77d85b304651949a819bc8b0a74819f0416.tar.gz |
script: Attempt to decompress images in place
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | perf/cairo-perf-trace.c | 16 | ||||
-rw-r--r-- | util/cairo-script/cairo-script-interpreter.h | 7 | ||||
-rw-r--r-- | util/cairo-script/cairo-script-operators.c | 391 |
3 files changed, 247 insertions, 167 deletions
diff --git a/perf/cairo-perf-trace.c b/perf/cairo-perf-trace.c index bd0cb07d1..4b8c85eab 100644 --- a/perf/cairo-perf-trace.c +++ b/perf/cairo-perf-trace.c @@ -299,6 +299,19 @@ _similar_surface_create (void *closure, return surface; } +static cairo_surface_t * +_source_image_create (void *closure, + cairo_format_t format, + int width, + int height, + long uid) +{ + struct trace *args = closure; + + return cairo_surface_create_similar_image (args->surface, + format, width, height); +} + static cairo_t * _context_create (void *closure, cairo_surface_t *surface) @@ -643,7 +656,8 @@ cairo_perf_trace (cairo_perf_t *perf, _context_create, NULL, /* context_destroy */ NULL, /* show_page */ - NULL /* copy_page */ + NULL, /* copy_page */ + _source_image_create, }; args.tile_size = perf->tile_size; diff --git a/util/cairo-script/cairo-script-interpreter.h b/util/cairo-script/cairo-script-interpreter.h index bbdd15d38..27fb98661 100644 --- a/util/cairo-script/cairo-script-interpreter.h +++ b/util/cairo-script/cairo-script-interpreter.h @@ -65,6 +65,12 @@ typedef void (*csi_copy_page_func_t) (void *closure, cairo_t *cr); +typedef cairo_surface_t * +(*csi_create_source_image_t) (void *closure, + cairo_format_t format, + int width, int height, + long uid); + typedef struct _cairo_script_interpreter_hooks { void *closure; csi_surface_create_func_t surface_create; @@ -73,6 +79,7 @@ typedef struct _cairo_script_interpreter_hooks { csi_destroy_func_t context_destroy; csi_show_page_func_t show_page; csi_copy_page_func_t copy_page; + csi_create_source_image_t create_source_image; } cairo_script_interpreter_hooks_t; cairo_public cairo_script_interpreter_t * diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c index 9ba24f8fb..efc1970cf 100644 --- a/util/cairo-script/cairo-script-operators.c +++ b/util/cairo-script/cairo-script-operators.c @@ -2892,7 +2892,8 @@ _ifelse (csi_t *ctx) } static csi_status_t -_image_read_raw (csi_file_t *src, +_image_read_raw (csi_t *ctx, + csi_object_t *src, cairo_format_t format, int width, int height, cairo_surface_t **image_out) @@ -2902,20 +2903,34 @@ _image_read_raw (csi_file_t *src, int rem, len, ret, x, rowlen, instride, stride; cairo_status_t status; - stride = cairo_format_stride_for_width (format, width); - data = malloc (stride * height); - if (data == NULL) - return CAIRO_STATUS_NO_MEMORY; + if (width == 0 || height == 0) { + *image_out = cairo_image_surface_create (format, 0, 0); + return CSI_STATUS_SUCCESS; + } - image = cairo_image_surface_create_for_data (data, format, - width, height, stride); - status = cairo_surface_set_user_data (image, - (const cairo_user_data_key_t *) image, - data, free); - if (status) { - cairo_surface_destroy (image); - free (image); - return status; + if (ctx->hooks.create_source_image != NULL) { + image = ctx->hooks.create_source_image (ctx->hooks.closure, + format, width, height, + 0); + + stride = cairo_image_surface_get_stride (image); + data = cairo_image_surface_get_data (image); + } else { + stride = cairo_format_stride_for_width (format, width); + data = malloc (stride * height); + if (data == NULL) + return CAIRO_STATUS_NO_MEMORY; + + image = cairo_image_surface_create_for_data (data, format, + width, height, stride); + status = cairo_surface_set_user_data (image, + (const cairo_user_data_key_t *) image, + data, free); + if (status) { + cairo_surface_destroy (image); + free (image); + return status; + } } switch (format) { @@ -2941,192 +2956,236 @@ _image_read_raw (csi_file_t *src, } len = rowlen * height; - bp = data; - rem = len; - while (rem) { - ret = csi_file_read (src, bp, rem); - if (_csi_unlikely (ret == 0)) { + if (rowlen == instride && + src->type == CSI_OBJECT_TYPE_STRING && + len == src->datum.string->deflate) + { + csi_string_t *s = src->datum.string; + unsigned long out; + + switch (s->method) { + default: + case NONE: +err_decompress: cairo_surface_destroy (image); return _csi_error (CSI_STATUS_READ_ERROR); + +#if HAVE_ZLIB + case ZLIB: + if (uncompress ((Bytef *) data, &out, + (Bytef *) s->string, s->len) != Z_OK) + goto err_decompress; + break; +#endif + +#if HAVE_LZO + case LZO: + if (lzo2a_decompress ((Bytef *) s->string, s->len, + (Bytef *) data, &out, + NULL)) + goto err_decompress; + break; +#endif } - rem -= ret; - bp += ret; } + else + { + csi_object_t file; + + status = csi_object_as_file (ctx, src, &file); + if (_csi_unlikely (status)) { + cairo_surface_destroy (image); + return status; + } + + bp = data; + rem = len; + while (rem) { + ret = csi_file_read (file.datum.file, bp, rem); + if (_csi_unlikely (ret == 0)) { + cairo_surface_destroy (image); + return _csi_error (CSI_STATUS_READ_ERROR); + } + rem -= ret; + bp += ret; + } - if (len != height * stride) { - while (--height) { - uint8_t *row = data + height * stride; + if (len != height * stride) { + while (--height) { + uint8_t *row = data + height * stride; + + /* XXX pixel conversion */ + switch (format) { + case CAIRO_FORMAT_A1: + for (x = rowlen; x--; ) { + uint8_t byte = *--bp; + row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte); + } + break; + case CAIRO_FORMAT_A8: + for (x = width; x--; ) + row[x] = *--bp; + break; + case CAIRO_FORMAT_RGB16_565: + for (x = width; x--; ) { +#ifdef WORDS_BIGENDIAN + row[2*x + 1] = *--bp; + row[2*x + 0] = *--bp; +#else + row[2*x + 0] = *--bp; + row[2*x + 1] = *--bp; +#endif + } + break; + case CAIRO_FORMAT_RGB24: + for (x = width; x--; ) { +#ifdef WORDS_BIGENDIAN + row[4*x + 3] = *--bp; + row[4*x + 2] = *--bp; + row[4*x + 1] = *--bp; + row[4*x + 0] = 0xff; +#else + row[4*x + 0] = *--bp; + row[4*x + 1] = *--bp; + row[4*x + 2] = *--bp; + row[4*x + 3] = 0xff; +#endif + } + break; + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_ARGB32: + /* stride == width */ + break; + } - /* XXX pixel conversion */ + memset (row + instride, 0, stride - instride); + } + + /* need to treat last row carefully */ switch (format) { case CAIRO_FORMAT_A1: for (x = rowlen; x--; ) { uint8_t byte = *--bp; - row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte); + data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte); } break; case CAIRO_FORMAT_A8: for (x = width; x--; ) - row[x] = *--bp; + data[x] = *--bp; break; case CAIRO_FORMAT_RGB16_565: for (x = width; x--; ) { #ifdef WORDS_BIGENDIAN - row[2*x + 1] = *--bp; - row[2*x + 0] = *--bp; + data[2*x + 1] = *--bp; + data[2*x + 0] = *--bp; #else - row[2*x + 0] = *--bp; - row[2*x + 1] = *--bp; + data[2*x + 0] = *--bp; + data[2*x + 1] = *--bp; #endif } break; case CAIRO_FORMAT_RGB24: - for (x = width; x--; ) { + for (x = width; --x>1; ) { #ifdef WORDS_BIGENDIAN - row[4*x + 3] = *--bp; - row[4*x + 2] = *--bp; - row[4*x + 1] = *--bp; - row[4*x + 0] = 0xff; + data[4*x + 3] = *--bp; + data[4*x + 2] = *--bp; + data[4*x + 1] = *--bp; + data[4*x + 0] = 0xff; #else - row[4*x + 0] = *--bp; - row[4*x + 1] = *--bp; - row[4*x + 2] = *--bp; - row[4*x + 3] = 0xff; + data[4*x + 0] = *--bp; + data[4*x + 1] = *--bp; + data[4*x + 2] = *--bp; + data[4*x + 3] = 0xff; #endif } - break; - case CAIRO_FORMAT_RGB30: - case CAIRO_FORMAT_INVALID: - case CAIRO_FORMAT_ARGB32: - /* stride == width */ - break; - } - - memset (row + instride, 0, stride - instride); - } - - /* need to treat last row carefully */ - switch (format) { - case CAIRO_FORMAT_A1: - for (x = rowlen; x--; ) { - uint8_t byte = *--bp; - data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte); - } - break; - case CAIRO_FORMAT_A8: - for (x = width; x--; ) - data[x] = *--bp; - break; - case CAIRO_FORMAT_RGB16_565: - for (x = width; x--; ) { + if (width > 1) { + uint8_t rgb[2][3]; + /* shuffle the last couple of overlapping pixels */ + rgb[1][0] = data[5]; + rgb[1][1] = data[4]; + rgb[1][2] = data[3]; + rgb[0][0] = data[2]; + rgb[0][1] = data[1]; + rgb[0][2] = data[0]; #ifdef WORDS_BIGENDIAN - data[2*x + 1] = *--bp; - data[2*x + 0] = *--bp; + data[4] = 0xff; + data[5] = rgb[1][2]; + data[6] = rgb[1][1]; + data[7] = rgb[1][0]; + data[0] = 0xff; + data[1] = rgb[0][2]; + data[2] = rgb[0][1]; + data[3] = rgb[0][0]; #else - data[2*x + 0] = *--bp; - data[2*x + 1] = *--bp; + data[7] = 0xff; + data[6] = rgb[1][2]; + data[5] = rgb[1][1]; + data[4] = rgb[1][0]; + data[3] = 0xff; + data[2] = rgb[0][2]; + data[1] = rgb[0][1]; + data[0] = rgb[0][0]; #endif - } - break; - case CAIRO_FORMAT_RGB24: - for (x = width; --x>1; ) { -#ifdef WORDS_BIGENDIAN - data[4*x + 3] = *--bp; - data[4*x + 2] = *--bp; - data[4*x + 1] = *--bp; - data[4*x + 0] = 0xff; -#else - data[4*x + 0] = *--bp; - data[4*x + 1] = *--bp; - data[4*x + 2] = *--bp; - data[4*x + 3] = 0xff; -#endif - } - if (width > 1) { - uint8_t rgb[2][3]; - /* shuffle the last couple of overlapping pixels */ - rgb[1][0] = data[5]; - rgb[1][1] = data[4]; - rgb[1][2] = data[3]; - rgb[0][0] = data[2]; - rgb[0][1] = data[1]; - rgb[0][2] = data[0]; -#ifdef WORDS_BIGENDIAN - data[4] = 0xff; - data[5] = rgb[1][2]; - data[6] = rgb[1][1]; - data[7] = rgb[1][0]; - data[0] = 0xff; - data[1] = rgb[0][2]; - data[2] = rgb[0][1]; - data[3] = rgb[0][0]; -#else - data[7] = 0xff; - data[6] = rgb[1][2]; - data[5] = rgb[1][1]; - data[4] = rgb[1][0]; - data[3] = 0xff; - data[2] = rgb[0][2]; - data[1] = rgb[0][1]; - data[0] = rgb[0][0]; -#endif - } else { + } else { #ifdef WORDS_BIGENDIAN - data[0] = 0xff; - data[1] = data[0]; - data[2] = data[1]; - data[3] = data[2]; + data[0] = 0xff; + data[1] = data[0]; + data[2] = data[1]; + data[3] = data[2]; #else - data[3] = data[0]; - data[0] = data[2]; - data[2] = data[3]; - data[3] = 0xff; + data[3] = data[0]; + data[0] = data[2]; + data[2] = data[3]; + data[3] = 0xff; #endif + } + break; + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_ARGB32: + /* stride == width */ + break; } - break; - case CAIRO_FORMAT_RGB30: - case CAIRO_FORMAT_INVALID: - case CAIRO_FORMAT_ARGB32: - /* stride == width */ - break; - } - memset (data + instride, 0, stride - instride); - } else { + memset (data + instride, 0, stride - instride); + } else { #ifndef WORDS_BIGENDIAN - switch (format) { - case CAIRO_FORMAT_A1: - for (x = 0; x < len; x++) { - uint8_t byte = data[x]; - data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte); - } - break; - case CAIRO_FORMAT_RGB16_565: - { - uint32_t *rgba = (uint32_t *) data; - for (x = len/2; x--; rgba++) { - *rgba = bswap_16 (*rgba); + switch (format) { + case CAIRO_FORMAT_A1: + for (x = 0; x < len; x++) { + uint8_t byte = data[x]; + data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte); } - } - break; - case CAIRO_FORMAT_ARGB32: - { - uint32_t *rgba = (uint32_t *) data; - for (x = len/4; x--; rgba++) { - *rgba = bswap_32 (*rgba); + break; + case CAIRO_FORMAT_RGB16_565: + { + uint32_t *rgba = (uint32_t *) data; + for (x = len/2; x--; rgba++) { + *rgba = bswap_16 (*rgba); + } } - } - break; + break; + case CAIRO_FORMAT_ARGB32: + { + uint32_t *rgba = (uint32_t *) data; + for (x = len/4; x--; rgba++) { + *rgba = bswap_32 (*rgba); + } + } + break; - case CAIRO_FORMAT_A8: - break; + case CAIRO_FORMAT_A8: + break; - case CAIRO_FORMAT_RGB30: - case CAIRO_FORMAT_RGB24: - case CAIRO_FORMAT_INVALID: - default: - break; - } + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_INVALID: + default: + break; + } #endif + } + csi_object_free (ctx, &file); } cairo_surface_mark_dirty (image); @@ -3303,22 +3362,22 @@ _image_load_from_dictionary (csi_t *ctx, mime_type = MIME_TYPE_PNG; } - status = csi_object_as_file (ctx, &obj, &file); - if (_csi_unlikely (status)) - return status; /* XXX hook for general mime-type decoder */ switch (mime_type) { case MIME_TYPE_NONE: - status = _image_read_raw (file.datum.file, - format, width, height, &image); + status = _image_read_raw (ctx, &obj, format, width, height, &image); break; case MIME_TYPE_PNG: + status = csi_object_as_file (ctx, &obj, &file); + if (_csi_unlikely (status)) + return status; + status = _image_read_png (file.datum.file, &image); + csi_object_free (ctx, &file); break; } - csi_object_free (ctx, &file); if (_csi_unlikely (status)) return status; |