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.



SVN revision: 42507
This commit is contained in:
Carsten Haitzler 2009-09-16 09:48:05 +00:00
parent ed7064edcc
commit 65f147aa81
13 changed files with 202 additions and 84 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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))

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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 */

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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)
{