When icons had a very small aspect ratio, we crashed, don't.
[dana/openbox.git] / render / image.c
index d0633d9..9648643 100644 (file)
@@ -40,6 +40,14 @@ void RrImagePicInit(RrImagePic *pic, gint w, gint h, RrPixel32 *data)
         pic->sum += *(data++);
 }
 
+static void RrImagePicFree(RrImagePic *pic)
+{
+    if (pic) {
+        g_free(pic->data);
+        g_free(pic);
+    }
+}
+
 /*! Add a picture to an Image, that is, add another copy of the image at
   another size.  This may add it to the "originals" list or to the
   "resized" list. */
@@ -67,7 +75,7 @@ static void AddPicture(RrImage *self, RrImagePic ***list, gint *len,
 
 #ifdef DEBUG
     g_message("Adding %s picture to the cache:\n    "
-              "Image 0x%x, w %d h %d Hash %u\n",
+              "Image 0x%x, w %d h %d Hash %u",
               (*list == self->original ? "ORIGINAL" : "RESIZED"),
               (guint)self, pic->width, pic->height, RrImagePicHash(pic));
 #endif
@@ -82,7 +90,7 @@ static void RemovePicture(RrImage *self, RrImagePic ***list,
 
 #ifdef DEBUG
     g_message("Removing %s picture from the cache:\n    "
-              "Image 0x%x, w %d h %d Hash %u\n",
+              "Image 0x%x, w %d h %d Hash %u",
               (*list == self->original ? "ORIGINAL" : "RESIZED"),
               (guint)self, (*list)[i]->width, (*list)[i]->height,
               RrImagePicHash((*list)[i]));
@@ -91,9 +99,8 @@ static void RemovePicture(RrImage *self, RrImagePic ***list,
     /* remove the picture as a key in the cache */
     g_hash_table_remove(self->cache->table, (*list)[i]);
 
-    /* free the picture (and its rgba data) */
-    g_free((*list)[i]);
-    g_free((*list)[i]->data);
+    /* free the picture */
+    RrImagePicFree((*list)[i]);
     /* shift everything down one */
     for (j = i; j < *len-1; ++j)
         (*list)[j] = (*list)[j+1];
@@ -117,6 +124,12 @@ static RrImagePic* ResizeImage(RrPixel32 *src,
     gulong ratioX, ratioY;
     gulong aspectW, aspectH;
 
+    /* XXX should these variables be ensured to not be zero in the callers? */
+    srcW = srcW ? srcW : 1;
+    srcH = srcH ? srcH : 1;
+    dstW = dstW ? dstW : 1;
+    dstH = dstH ? dstH : 1;
+
     /* keep the aspect ratio */
     aspectW = dstW;
     aspectH = (gint)(dstW * ((gdouble)srcH / srcW));
@@ -124,11 +137,11 @@ static RrImagePic* ResizeImage(RrPixel32 *src,
         aspectH = dstH;
         aspectW = (gint)(dstH * ((gdouble)srcW / srcH));
     }
-    dstW = aspectW;
-    dstH = aspectH;
+    dstW = aspectW ? aspectW : 1;
+    dstH = aspectH ? aspectH : 1;
 
     if (srcW == dstW && srcH == dstH)
-        return NULL; /* no scaling needed ! */
+        return NULL; /* no scaling needed! */
 
     dststart = dst = g_new(RrPixel32, dstW * dstH);
 
@@ -287,6 +300,7 @@ void RrImageDrawRGBA(RrPixel32 *target, RrTextureRGBA *rgba,
             DrawRGBA(target, target_w, target_h,
                      scaled->data, scaled->width, scaled->height,
                      rgba->alpha, area);
+            RrImagePicFree(scaled);
     }
     else
         DrawRGBA(target, target_w, target_h,
@@ -317,7 +331,7 @@ void RrImageUnref(RrImage *self)
     if (self && --self->ref == 0) {
 #ifdef DEBUG
         g_message("Refcount to 0, removing ALL pictures from the cache:\n    "
-                  "Image 0x%x\n", (guint)self);
+                  "Image 0x%x", (guint)self);
 #endif
         while (self->n_original > 0)
             RemovePicture(self, &self->original, 0, &self->n_original);
@@ -340,7 +354,7 @@ void RrImageAddPicture(RrImage *self, RrPixel32 *data, gint w, gint h)
         if (self->original[i]->width == w && self->original[i]->height == h) {
 #ifdef DEBUG
             g_message("Found duplicate ORIGINAL image:\n    "
-                      "Image 0x%x, w %d h %d\n", (guint)self, w, h);
+                      "Image 0x%x, w %d h %d", (guint)self, w, h);
 #endif
             return;
         }
@@ -385,9 +399,11 @@ void RrImageDrawImage(RrPixel32 *target, RrTextureImage *img,
     gint i, min_diff, min_i, min_aspect_diff, min_aspect_i;
     RrImage *self;
     RrImagePic *pic;
+    gboolean free_pic;
 
     self = img->image;
     pic = NULL;
+    free_pic = FALSE;
 
     /* is there an original of this size? (only w or h has to be right cuz
        we maintain aspect ratios) */
@@ -474,6 +490,8 @@ void RrImageDrawImage(RrPixel32 *target, RrTextureImage *img,
         if (self->cache->max_resized_saved)
             /* add it to the top of the resized list */
             AddPicture(self, &self->resized, &self->n_resized, pic);
+        else
+            free_pic = TRUE; /* don't leak mem! */
     }
 
     g_assert(pic != NULL);
@@ -481,4 +499,6 @@ void RrImageDrawImage(RrPixel32 *target, RrTextureImage *img,
     DrawRGBA(target, target_w, target_h,
              pic->data, pic->width, pic->height,
              img->alpha, area);
+    if (free_pic)
+        RrImagePicFree(pic);
 }