make loaders use "big image" macro to detect an image that is going to just
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 16 Sep 2009 09:48:05 +0000 (09:48 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 16 Sep 2009 09:48:05 +0000 (09:48 +0000)
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: http://svn.enlightenment.org/svn/e/trunk/evas@42507 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

13 files changed:
src/lib/cache/evas_cache_engine_image.c
src/lib/cache/evas_cache_image.c
src/lib/engines/common/evas_image_load.c
src/lib/engines/common/evas_image_main.c
src/lib/include/evas_common.h
src/modules/loaders/edb/evas_image_load_edb.c
src/modules/loaders/eet/evas_image_load_eet.c
src/modules/loaders/gif/evas_image_load_gif.c
src/modules/loaders/jpeg/evas_image_load_jpeg.c
src/modules/loaders/png/evas_image_load_png.c
src/modules/loaders/svg/evas_image_load_svg.c
src/modules/loaders/tiff/evas_image_load_tiff.c
src/modules/loaders/xpm/evas_image_load_xpm.c

index d01dcc1..71ef944 100644 (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);
index d1ffb74..a80c413 100644 (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;
index 9ab8a6d..baf7361 100644 (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;
index aa3e988..35c02b8 100644 (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))
index 93386de..b8ed69d 100644 (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
index f2a3c3d..59f10ae 100644 (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);
index 9e7f84a..f3d2819 100644 (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,
index ecc4a95..5269f4a 100644 (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;
index aeadc62..8e648c5 100644 (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 */
index 6c4e147..2e6738f 100644 (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;
index 16de052..cf014fd 100644 (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);
index c5379b8..e8bb74f 100644 (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;
index b062690..46519ce 100644 (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)
                          {