From 84ee9f75593ae5808a8ceadb33e6aff035417462 Mon Sep 17 00:00:00 2001 From: raster Date: Wed, 16 Sep 2009 09:48:05 +0000 Subject: [PATCH] make loaders use "big image" macro to detect an image that is going to just be way too big to ever allocate. probably code can do with other fixes too. also make jpeg loader rudametarily understand load regions. very brute-force. but enough for just this moment to do testing. git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/evas@42507 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- src/lib/cache/evas_cache_engine_image.c | 2 +- src/lib/cache/evas_cache_image.c | 125 +++++++++++++++--------- src/lib/engines/common/evas_image_load.c | 14 +-- src/lib/engines/common/evas_image_main.c | 2 +- src/lib/include/evas_common.h | 6 +- src/modules/loaders/edb/evas_image_load_edb.c | 6 +- src/modules/loaders/eet/evas_image_load_eet.c | 2 + src/modules/loaders/gif/evas_image_load_gif.c | 3 +- src/modules/loaders/jpeg/evas_image_load_jpeg.c | 108 ++++++++++++++++---- src/modules/loaders/png/evas_image_load_png.c | 3 +- src/modules/loaders/svg/evas_image_load_svg.c | 3 +- src/modules/loaders/tiff/evas_image_load_tiff.c | 3 +- src/modules/loaders/xpm/evas_image_load_xpm.c | 9 ++ 13 files changed, 202 insertions(+), 84 deletions(-) diff --git a/src/lib/cache/evas_cache_engine_image.c b/src/lib/cache/evas_cache_engine_image.c index d01dcc1..71ef944 100644 --- a/src/lib/cache/evas_cache_engine_image.c +++ b/src/lib/cache/evas_cache_engine_image.c @@ -620,7 +620,7 @@ evas_cache_engine_image_load_data(Engine_Image_Entry *eim) assert(eim->src); assert(eim->cache); - if (eim->flags.loaded) return ; + if (eim->flags.loaded) return; if (eim->src) evas_cache_image_load_data(eim->src); diff --git a/src/lib/cache/evas_cache_image.c b/src/lib/cache/evas_cache_image.c index d1ffb74..a80c413 100644 --- a/src/lib/cache/evas_cache_image.c +++ b/src/lib/cache/evas_cache_image.c @@ -46,7 +46,7 @@ static pthread_t tid = 0; static Eina_Bool running = EINA_FALSE; -static void* _evas_cache_background_load(void *); +static void *_evas_cache_background_load(void *); #endif #define FREESTRC(Var) \ @@ -317,7 +317,7 @@ _evas_cache_image_async_call__locked(Image_Entry *im) while (im->targets) { Evas_Cache_Target *tmp = im->targets; - + evas_async_events_put(tmp->target, EVAS_CALLBACK_IMAGE_PRELOADED, NULL, (void (*)(void*, Evas_Callback_Type, void*))evas_object_event_callback_call); im->targets = (Evas_Cache_Target*) eina_inlist_remove(EINA_INLIST_GET(im->targets), EINA_INLIST_GET(im->targets)); @@ -411,34 +411,38 @@ _evas_cache_image_entry_preload_remove(Image_Entry *ie, const void *target) if (l->ie == ie) { Evas_Cache_Target *tg; - - if (target) { - EINA_INLIST_FOREACH(ie->targets, tg) - { - if (tg->target == target) { - ie->targets = (Evas_Cache_Target*) eina_inlist_remove(EINA_INLIST_GET(ie->targets), EINA_INLIST_GET(tg)); - free(tg); - break; - } - } - } else { - _evas_cache_image_async_call__locked(ie); - - while (ie->targets) - { - tg = ie->targets; - ie->targets = (Evas_Cache_Target*) eina_inlist_remove(EINA_INLIST_GET(ie->targets), EINA_INLIST_GET(tg)); - free(tg); - } - } - + + if (target) + { + EINA_INLIST_FOREACH(ie->targets, tg) + { + if (tg->target == target) + { + ie->targets = (Evas_Cache_Target*) eina_inlist_remove(EINA_INLIST_GET(ie->targets), EINA_INLIST_GET(tg)); + free(tg); + break; + } + } + } + else + { + _evas_cache_image_async_call__locked(ie); + + while (ie->targets) + { + tg = ie->targets; + ie->targets = (Evas_Cache_Target*) eina_inlist_remove(EINA_INLIST_GET(ie->targets), EINA_INLIST_GET(tg)); + free(tg); + } + } + if (!ie->targets) { preload = eina_inlist_remove(preload, EINA_INLIST_GET(l)); free(l); } - + break; } } @@ -622,7 +626,7 @@ evas_cache_image_request(Evas_Cache_Image *cache, const char *file, const char * file_length = strlen(file); key_length = key ? strlen(key) : 6; - size = file_length + key_length + 64; + size = file_length + key_length + 128; hkey = alloca(sizeof (char) * size); memcpy(hkey, file, file_length); @@ -639,13 +643,15 @@ evas_cache_image_request(Evas_Cache_Image *cache, const char *file, const char * (lo && (lo->scale_down_by == 0) && (lo->dpi == 0.0) && - ((lo->w == 0) || (lo->h == 0)))) + ((lo->w == 0) || (lo->h == 0)) && + ((lo->region.w == 0) || (lo->region.w == 0)) + )) { lo = &prevent; - if (key) - format = "%s//://%s"; - else - format = "%s//://%p"; +// if (key) +// format = "%s//://%s"; +// else +// format = "%s//://%p"; } else { @@ -668,6 +674,26 @@ evas_cache_image_request(Evas_Cache_Image *cache, const char *file, const char * size += 1; size += eina_convert_xtoa(lo->h, hkey + size); + + hkey[size] = '/'; + size += 1; + + size += eina_convert_xtoa(lo->region.x, hkey + size); + + hkey[size] = '+'; + size += 1; + + size += eina_convert_xtoa(lo->region.y, hkey + size); + + hkey[size] = '.'; + size += 1; + + size += eina_convert_xtoa(lo->region.w, hkey + size); + + hkey[size] = 'x'; + size += 1; + + size += eina_convert_xtoa(lo->region.h, hkey + size); } hkey[size] = '\0'; @@ -1242,15 +1268,15 @@ static void* _evas_cache_background_load(void *data) { (void) data; - - restart: + + restart: while (preload) { pthread_mutex_lock(&mutex); if (preload) { Evas_Cache_Preload *tmp = (Evas_Cache_Preload*) preload; - + current = tmp->ie; preload = eina_inlist_remove(preload, preload); @@ -1270,21 +1296,24 @@ _evas_cache_background_load(void *data) current->channel++; cache = current->cache; - error = cache->func.load(current); - if (cache->func.debug) - cache->func.debug("load", current); - - if (error) - { - _evas_cache_image_entry_surface_alloc(cache, current, - current->w, current->h); - current->flags.loaded = 0; - } - else - { - current->flags.loaded = 1; - } - + if (!current->flags.loaded) + { + error = cache->func.load(current); + if (cache->func.debug) + cache->func.debug("load", current); + + if (error) + { + _evas_cache_image_entry_surface_alloc(cache, current, + current->w, current->h); + current->flags.loaded = 0; + } + else + { + current->flags.loaded = 1; + } + } + current->flags.preload = 0; current->channel = pchannel; diff --git a/src/lib/engines/common/evas_image_load.c b/src/lib/engines/common/evas_image_load.c index 9ab8a6d..baf7361 100644 --- a/src/lib/engines/common/evas_image_load.c +++ b/src/lib/engines/common/evas_image_load.c @@ -46,9 +46,9 @@ _evas_image_foreach_loader(const Eina_Hash *hash, const char *key, Evas_Module * evas_module_use(em); if (evas_image_load_func && evas_image_load_func->file_head(ie, ie->file, ie->key)) { - ie->info.module = (void*) em; - ie->info.loader = (void*) evas_image_load_func; - evas_module_ref((Evas_Module*) ie->info.module); + ie->info.module = (void *)em; + ie->info.loader = (void *)evas_image_load_func; + evas_module_ref((Evas_Module *)ie->info.module); return EINA_FALSE; } @@ -79,7 +79,7 @@ evas_common_load_rgba_image_module_from_file(Image_Entry *ie) { for (i = 0, ++dot; i < (sizeof (loaders) / sizeof (struct ext_loader_s)); ++i) { - if (!strcasecmp (dot, loaders[i].extention)) + if (!strcasecmp(dot, loaders[i].extention)) { loader = loaders[i].loader; break; @@ -108,7 +108,7 @@ evas_common_load_rgba_image_module_from_file(Image_Entry *ie) /* This is our last chance, try all known image loader. */ /* FIXME: We could use eina recursive module search ability. */ - for (i = 0; i < sizeof (loaders_name) / sizeof (char *); ++i) + for (i = 0; i < sizeof (loaders_name) / sizeof (char *); i++) { em = evas_module_find_type(EVAS_MODULE_TYPE_IMAGE_LOADER, loaders_name[i]); if (em) @@ -165,7 +165,9 @@ evas_common_load_rgba_image_data_from_file(Image_Entry *ie) evas_image_load_func = ie->info.loader; evas_module_use((Evas_Module*) ie->info.module); if (!evas_image_load_func->file_data(ie, ie->file, ie->key)) - return -1; + { + return -1; + } // evas_module_unref((Evas_Module*) ie->info.module); // ie->info.module = NULL; diff --git a/src/lib/engines/common/evas_image_main.c b/src/lib/engines/common/evas_image_main.c index aa3e988..35c02b8 100644 --- a/src/lib/engines/common/evas_image_main.c +++ b/src/lib/engines/common/evas_image_main.c @@ -175,7 +175,7 @@ evas_common_rgba_image_unload(Image_Entry *ie) if (!ie->flags.loaded) return; if ((!ie->info.module) && (!ie->data1)) return; if (!ie->file) return; - + ie->flags.loaded = 0; if ((im->cs.data) && (im->image.data)) diff --git a/src/lib/include/evas_common.h b/src/lib/include/evas_common.h index 93386de..b8ed69d 100644 --- a/src/lib/include/evas_common.h +++ b/src/lib/include/evas_common.h @@ -166,7 +166,11 @@ void *alloca (size_t); /* use exact rects for updates not tiles */ /* #define RECTUPDATE */ #define TILESIZE 8 -#define IMG_MAX_SIZE 65536 +#define IMG_MAX_SIZE 65000 + +#define IMG_TOO_BIG(w, h) \ + ((((unsigned long long)w) * ((unsigned long long)h)) > \ + (1 << (29 * (sizeof(void *) / 4)))) #ifdef BUILD_SMALL_DITHER_MASK # define DM_TABLE _evas_dither_44 diff --git a/src/modules/loaders/edb/evas_image_load_edb.c b/src/modules/loaders/edb/evas_image_load_edb.c index f2a3c3d..59f10ae 100644 --- a/src/modules/loaders/edb/evas_image_load_edb.c +++ b/src/modules/loaders/edb/evas_image_load_edb.c @@ -56,7 +56,8 @@ evas_image_load_file_head_edb(Image_Entry *ie, const char *file, const char *key } w = header[1]; h = header[2]; - if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE)) + if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) || + IMG_TOO_BIG(w, h)) { free(ret); e_db_close(db); @@ -120,7 +121,8 @@ evas_image_load_file_data_edb(Image_Entry *ie, const char *file, const char *key } w = header[1]; h = header[2]; - if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE)) + if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) || + IMG_TOO_BIG(w, h)) { free(ret); e_db_close(db); diff --git a/src/modules/loaders/eet/evas_image_load_eet.c b/src/modules/loaders/eet/evas_image_load_eet.c index 9e7f84a..f3d2819 100644 --- a/src/modules/loaders/eet/evas_image_load_eet.c +++ b/src/modules/loaders/eet/evas_image_load_eet.c @@ -32,6 +32,7 @@ evas_image_load_file_head_eet(Image_Entry *ie, const char *file, const char *key if (!ef) return 0; ok = eet_data_image_header_read(ef, key, &w, &h, &alpha, &compression, &quality, &lossy); + if (IMG_TOO_BIG(w, h)) goto on_error; if (!ok) goto on_error; if (alpha) ie->flags.alpha = 1; ie->w = w; @@ -59,6 +60,7 @@ evas_image_load_file_data_eet(Image_Entry *ie, const char *file, const char *key if (!ef) return 0; ok = eet_data_image_header_read(ef, key, &w, &h, &alpha, &compression, &quality, &lossy); + if (IMG_TOO_BIG(w, h)) goto on_error; if (!ok) goto on_error; evas_cache_image_surface_alloc(ie, w, h); ok = eet_data_image_read_to_surface(ef, key, 0, 0, diff --git a/src/modules/loaders/gif/evas_image_load_gif.c b/src/modules/loaders/gif/evas_image_load_gif.c index ecc4a95..5269f4a 100644 --- a/src/modules/loaders/gif/evas_image_load_gif.c +++ b/src/modules/loaders/gif/evas_image_load_gif.c @@ -65,7 +65,8 @@ evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key } w = gif->Image.Width; h = gif->Image.Height; - if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE)) + if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) || + IMG_TOO_BIG(w, h)) { DGifCloseFile(gif); return 0; diff --git a/src/modules/loaders/jpeg/evas_image_load_jpeg.c b/src/modules/loaders/jpeg/evas_image_load_jpeg.c index aeadc62..8e648c5d 100644 --- a/src/modules/loaders/jpeg/evas_image_load_jpeg.c +++ b/src/modules/loaders/jpeg/evas_image_load_jpeg.c @@ -104,13 +104,8 @@ evas_image_load_file_head_jpeg_internal(Image_Entry *ie, FILE *f) /* head decoding */ w = cinfo.output_width; h = cinfo.output_height; - if ((ie->load_opts.region.w > 0) && (ie->load_opts.region.h > 0)) - { - RECTS_CLIP_TO_RECT(ie->load_opts.region.x, ie->load_opts.region.y, - ie->load_opts.region.w, ie->load_opts.region.h, - 0, 0, w, h); - } - if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE)) + if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) || + (IMG_TOO_BIG(w, h))) { jpeg_destroy_decompress(&cinfo); return 0; @@ -182,9 +177,23 @@ evas_image_load_file_head_jpeg_internal(Image_Entry *ie, FILE *f) jpeg_start_decompress(&cinfo); } - // FIXME: handle region if specified ie->w = cinfo.output_width; ie->h = cinfo.output_height; + + // be nice and clip region to image. if its totally outside, fail load + if ((ie->load_opts.region.w > 0) && (ie->load_opts.region.h > 0)) + { + RECTS_CLIP_TO_RECT(ie->load_opts.region.x, ie->load_opts.region.y, + ie->load_opts.region.w, ie->load_opts.region.h, + 0, 0, ie->w, ie->h); + if ((ie->load_opts.region.w <= 0) || (ie->load_opts.region.h <= 0)) + { + jpeg_destroy_decompress(&cinfo); + return 0; + } + ie->w = ie->load_opts.region.w; + ie->h = ie->load_opts.region.h; + } /* end head decoding */ jpeg_destroy_decompress(&cinfo); @@ -200,6 +209,7 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie, FILE *f) DATA8 *ptr, *line[16], *data; DATA32 *ptr2; int x, y, l, i, scans, count; + int region = 0; if (!f) return 0; cinfo.err = jpeg_std_error(&(jerr.pub)); @@ -250,10 +260,19 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie, FILE *f) w = cinfo.output_width; h = cinfo.output_height; + if ((ie->load_opts.region.w > 0) && (ie->load_opts.region.h > 0)) + region = 1; if ((w != ie->w) || (h != ie->h)) { - jpeg_destroy_decompress(&cinfo); - return 0; + // OK. region decode happening. a sub-set of the image +// jpeg_destroy_decompress(&cinfo); +// return 0; + } + if ((region) && + ((ie->w != ie->load_opts.region.w) || (ie->h != ie->load_opts.region.h))) + { + ie->w = ie->load_opts.region.w; + ie->h = ie->load_opts.region.h; } if (!(((cinfo.out_color_space == JCS_RGB) && @@ -272,17 +291,18 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie, FILE *f) return 0; } data = alloca(w * 16 * cinfo.output_components); - evas_cache_image_surface_alloc(ie, w, h); + evas_cache_image_surface_alloc(ie, ie->w, ie->h); if (ie->flags.loaded) { jpeg_destroy_decompress(&cinfo); - return 0; + return 1; } ptr2 = evas_cache_image_pixels(ie); count = 0; /* We handle first CMYK (4 components) */ if (cinfo.output_components == 4) { + // FIXME: handle region for (i = 0; i < cinfo.rec_outbuf_height; i++) line[i] = data + (i * w * 4); for (l = 0; l < h; l += cinfo.rec_outbuf_height) @@ -331,6 +351,17 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie, FILE *f) /* We handle then RGB with 3 components */ else if (cinfo.output_components == 3) { + if (region) + { + printf("R| %p %5ix%5i %s: %5i %5i %5ix%5i\n", + ie, + ie->w, ie->h, + ie->file, + ie->load_opts.region.x, + ie->load_opts.region.y, + ie->load_opts.region.w, + ie->load_opts.region.h); + } for (i = 0; i < cinfo.rec_outbuf_height; i++) line[i] = data + (i * w * 3); for (l = 0; l < h; l += cinfo.rec_outbuf_height) @@ -339,16 +370,51 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie, FILE *f) scans = cinfo.rec_outbuf_height; if ((h - l) < scans) scans = h - l; ptr = data; - for (y = 0; y < scans; y++) - { - for (x = 0; x < w; x++) - { - *ptr2 = - (0xff000000) | ((ptr[0]) << 16) | ((ptr[1]) << 8) | (ptr[2]); - ptr += 3; - ptr2++; - } + if (!region) + { + for (y = 0; y < scans; y++) + { + for (x = 0; x < w; x++) + { + *ptr2 = + (0xff000000) | ((ptr[0]) << 16) | ((ptr[1]) << 8) | (ptr[2]); + ptr += 3; + ptr2++; + } + } } + else + { + // if line # > region last line, break + if (l >= (ie->load_opts.region.y + ie->load_opts.region.h)) + { + jpeg_destroy_decompress(&cinfo); + return 1; + } + // els if scan block intersects region start or later + else if ((l + scans) > + (ie->load_opts.region.y)) + { + for (y = 0; y < scans; y++) + { + if (((y + l) >= ie->load_opts.region.y) && + ((y + l) < (ie->load_opts.region.y + ie->load_opts.region.h))) + { + ptr += (3 * ie->load_opts.region.x); + for (x = 0; x < ie->load_opts.region.w; x++) + { + *ptr2 = + (0xff000000) | ((ptr[0]) << 16) | ((ptr[1]) << 8) | (ptr[2]); + ptr += 3; + ptr2++; + } + ptr += (3 * (w - (ie->load_opts.region.x + ie->load_opts.region.w))); + } + else + ptr += (3 * w); + } + } + } } } /* We finally handle RGB with 1 component */ diff --git a/src/modules/loaders/png/evas_image_load_png.c b/src/modules/loaders/png/evas_image_load_png.c index 6c4e147..2e6738f 100644 --- a/src/modules/loaders/png/evas_image_load_png.c +++ b/src/modules/loaders/png/evas_image_load_png.c @@ -85,7 +85,8 @@ evas_image_load_file_head_png(Image_Entry *ie, const char *file, const char *key png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *) (&w32), (png_uint_32 *) (&h32), &bit_depth, &color_type, &interlace_type, NULL, NULL); - if ((w32 < 1) || (h32 < 1) || (w32 > IMG_MAX_SIZE) || (h32 > IMG_MAX_SIZE)) + if ((w32 < 1) || (h32 < 1) || (w32 > IMG_MAX_SIZE) || (h32 > IMG_MAX_SIZE) || + IMG_TOO_BIG(w32, h32)) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); goto close_file; diff --git a/src/modules/loaders/svg/evas_image_load_svg.c b/src/modules/loaders/svg/evas_image_load_svg.c index 16de052..cf014fd 100644 --- a/src/modules/loaders/svg/evas_image_load_svg.c +++ b/src/modules/loaders/svg/evas_image_load_svg.c @@ -85,7 +85,8 @@ evas_image_load_file_head_svg(Image_Entry *ie, const char *file, const char *key rsvg_handle_get_dimensions(rsvg, &dim); w = dim.width; h = dim.height; - if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE)) + if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) || + IMG_TOO_BIG(w, h)) { // rsvg_handle_close(rsvg, NULL); g_object_unref(rsvg); diff --git a/src/modules/loaders/tiff/evas_image_load_tiff.c b/src/modules/loaders/tiff/evas_image_load_tiff.c index c5379b8..e8bb74f 100644 --- a/src/modules/loaders/tiff/evas_image_load_tiff.c +++ b/src/modules/loaders/tiff/evas_image_load_tiff.c @@ -174,7 +174,8 @@ evas_image_load_file_head_tiff(Image_Entry *ie, const char *file, const char *ke if (tiff_image.alpha != EXTRASAMPLE_UNSPECIFIED) ie->flags.alpha = 1; if ((tiff_image.width < 1) || (tiff_image.height < 1) || - (tiff_image.width > IMG_MAX_SIZE) || (tiff_image.height > IMG_MAX_SIZE)) + (tiff_image.width > IMG_MAX_SIZE) || (tiff_image.height > IMG_MAX_SIZE) || + IMG_TOO_BIG(tiff_image.width, tiff_image.height)) { TIFFClose(tif); return 0; diff --git a/src/modules/loaders/xpm/evas_image_load_xpm.c b/src/modules/loaders/xpm/evas_image_load_xpm.c index b062690..46519ce 100644 --- a/src/modules/loaders/xpm/evas_image_load_xpm.c +++ b/src/modules/loaders/xpm/evas_image_load_xpm.c @@ -245,6 +245,15 @@ evas_image_load_file_xpm(Image_Entry *ie, const char *file, const char *key __UN xpm_parse_done(); return 0; } + if (IMG_TOO_BIG(w, h)) + { + fprintf(stderr, + "XPM ERROR: Image just too big to ever allocate\n"); + free(line); + fclose(f); + xpm_parse_done(); + return 0; + } if (!cmap) { -- 2.7.4