]> Dogcows Code - chaz/openbox/blobdiff - render/image.c
Merge branch 'backport' into work
[chaz/openbox] / render / image.c
index 8ce3a57c7c27d441ae325a135f087b461f15b10e..79f47fe280829c6ad3a5d07f6f9846e38885f922 100644 (file)
 #define FLOOR(i)        ((i) & (~0UL << FRACTION))
 #define AVERAGE(a, b)   (((((a) ^ (b)) & 0xfefefefeL) >> 1) + ((a) & (b)))
 
+void RrImagePicInit(RrImagePic *pic, gint w, gint h, RrPixel32 *data)
+{
+    gint i;
+
+    pic->width = w;
+    pic->height = h;
+    pic->data = data;
+    pic->sum = 0;
+    for (i = w*h; i > 0; --i)
+        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. */
 static void AddPicture(RrImage *self, RrImagePic ***list, gint *len,
                        RrImagePic *pic)
 {
@@ -51,32 +74,33 @@ static void AddPicture(RrImage *self, RrImagePic ***list, gint *len,
     g_hash_table_insert(self->cache->table, (*list)[0], self);
 
 #ifdef DEBUG
-    g_print("Adding %s picture to the cache: "
-            "Image 0x%x, w %d h %d Hash %u\n",
+    g_debug("Adding %s picture to the cache:\n    "
+            "Image 0x%lx, w %d h %d Hash %u",
             (*list == self->original ? "ORIGINAL" : "RESIZED"),
-            (guint)self, pic->width, pic->height, RrImagePicHash(pic));
+            (gulong)self, pic->width, pic->height, RrImagePicHash(pic));
 #endif
 }
 
+/*! Remove a picture from an Image.  This may remove it from the "originals"
+  list or the "resized" list. */
 static void RemovePicture(RrImage *self, RrImagePic ***list,
                           gint i, gint *len)
 {
     gint j;
 
 #ifdef DEBUG
-    g_print("Removing %s picture from the cache: "
-            "Image 0x%x, w %d h %d Hash %u\n",
+    g_debug("Removing %s picture from the cache:\n    "
+            "Image 0x%lx, w %d h %d Hash %u",
             (*list == self->original ? "ORIGINAL" : "RESIZED"),
-            (guint)self, (*list)[i]->width, (*list)[i]->height,
+            (gulong)self, (*list)[i]->width, (*list)[i]->height,
             RrImagePicHash((*list)[i]));
 #endif
 
     /* 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];
@@ -84,17 +108,28 @@ static void RemovePicture(RrImage *self, RrImagePic ***list,
     *list = g_renew(RrImagePic*, *list, --*len);
 }
 
+/*! Given a picture in RGBA format, of a specified size, resize it to the new
+  requested size (but keep its aspect ratio).  If the image does not need to
+  be resized (it is already the right size) then this returns NULL.  Otherwise
+  it returns a newly allocated RrImagePic with the resized picture inside it
+*/
 static RrImagePic* ResizeImage(RrPixel32 *src,
-                                       gulong srcW, gulong srcH,
-                                       gulong dstW, gulong dstH)
+                               gulong srcW, gulong srcH,
+                               gulong dstW, gulong dstH)
 {
-    RrPixel32 *dst;
+    RrPixel32 *dst, *dststart;
     RrImagePic *pic;
     gulong dstX, dstY, srcX, srcY;
     gulong srcX1, srcX2, srcY1, srcY2;
     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));
@@ -102,17 +137,13 @@ 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! */
 
-    pic = g_new(RrImagePic, 1);
-    dst = g_new(RrPixel32, dstW * dstH);
-    pic->width = dstW;
-    pic->height = dstH;
-    pic->data = dst;
+    dststart = dst = g_new(RrPixel32, dstW * dstH);
 
     ratioX = (srcW << FRACTION) / dstW;
     ratioY = (srcH << FRACTION) / dstH;
@@ -184,10 +215,13 @@ static RrImagePic* ResizeImage(RrPixel32 *src,
         }
     }
 
+    pic = g_new(RrImagePic, 1);
+    RrImagePicInit(pic, dstW, dstH, dststart);
+
     return pic;
 }
 
-/*! This drawns an RGBA picture into the target, within the rectangle specified
+/*! This draws an RGBA picture into the target, within the rectangle specified
   by the area parameter.  If the area's size differs from the source's then it
   will be centered within the rectangle */
 void DrawRGBA(RrPixel32 *target, gint target_w, gint target_h,
@@ -199,6 +233,8 @@ void DrawRGBA(RrPixel32 *target, gint target_w, gint target_h,
     gint dw, dh;
 
     g_assert(source_w <= area->width && source_h <= area->height);
+    g_assert(area->x + area->width <= target_w);
+    g_assert(area->y + area->height <= target_h);
 
     /* keep the aspect ratio */
     dw = area->width;
@@ -246,6 +282,7 @@ void DrawRGBA(RrPixel32 *target, gint target_w, gint target_h,
     }
 }
 
+/*! Draw an RGBA texture into a target pixel buffer. */
 void RrImageDrawRGBA(RrPixel32 *target, RrTextureRGBA *rgba,
                      gint target_w, gint target_h,
                      RrRect *area)
@@ -263,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,
@@ -270,10 +308,13 @@ void RrImageDrawRGBA(RrPixel32 *target, RrTextureRGBA *rgba,
                  rgba->alpha, area);
 }
 
+/*! Create a new RrImage, which is linked to an image cache */
 RrImage* RrImageNew(RrImageCache *cache)
 {
     RrImage *self;
 
+    g_assert(cache != NULL);
+
     self = g_new0(RrImage, 1);
     self->ref = 1;
     self->cache = cache;
@@ -289,8 +330,8 @@ void RrImageUnref(RrImage *self)
 {
     if (self && --self->ref == 0) {
 #ifdef DEBUG
-        g_print("Refcount to 0, removing ALL pictures from the cache: "
-                  "Image 0x%x\n", (guint)self);
+        g_debug("Refcount to 0, removing ALL pictures from the cache:\n    "
+                "Image 0x%lx", (gulong)self);
 #endif
         while (self->n_original > 0)
             RemovePicture(self, &self->original, 0, &self->n_original);
@@ -300,6 +341,9 @@ void RrImageUnref(RrImage *self)
     }
 }
 
+/*! Add a new picture with the given RGBA pixel data and dimensions into the
+  RrImage.  This adds an "original" picture to the image.
+*/
 void RrImageAddPicture(RrImage *self, RrPixel32 *data, gint w, gint h)
 {
     gint i;
@@ -309,8 +353,8 @@ void RrImageAddPicture(RrImage *self, RrPixel32 *data, gint w, gint h)
     for (i = 0; i < self->n_original; ++i)
         if (self->original[i]->width == w && self->original[i]->height == h) {
 #ifdef DEBUG
-            g_print("Found duplicate ORIGINAL image: "
-                    "Image 0x%x, w %d h %d\n", (guint)self, w, h);
+            g_debug("Found duplicate ORIGINAL image:\n    "
+                    "Image 0x%lx, w %d h %d", (gulong)self, w, h);
 #endif
             return;
         }
@@ -324,12 +368,13 @@ void RrImageAddPicture(RrImage *self, RrPixel32 *data, gint w, gint h)
 
     /* add the new picture */
     pic = g_new(RrImagePic, 1);
-    pic->width = w;
-    pic->height = h;
-    pic->data = g_memdup(data, w*h*sizeof(RrPixel32));
+    RrImagePicInit(pic, w, h, g_memdup(data, w*h*sizeof(RrPixel32)));
     AddPicture(self, &self->original, &self->n_original, pic);
 }
 
+/*! Remove the picture from the RrImage which has the given dimensions. This
+ removes an "original" picture from the image.
+*/
 void RrImageRemovePicture(RrImage *self, gint w, gint h)
 {
     gint i;
@@ -342,6 +387,11 @@ void RrImageRemovePicture(RrImage *self, gint w, gint h)
         }
 }
 
+/*! Draw an RrImage texture into a target pixel buffer.  If the RrImage does
+  not contain a picture of the appropriate size, then one of its "original"
+  pictures will be resized and used (and stored in the RrImage as a "resized"
+  picture).
+ */
 void RrImageDrawImage(RrPixel32 *target, RrTextureImage *img,
                       gint target_w, gint target_h,
                       RrRect *area)
@@ -349,15 +399,19 @@ 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) */
+    /* is there an original of this size? (only the larger of
+       w or h has to be right cuz we maintain aspect ratios) */
     for (i = 0; i < self->n_original; ++i)
-        if (self->original[i]->width == area->width ||
-            self->original[i]->height == area->height)
+        if ((self->original[i]->width >= self->original[i]->height &&
+             self->original[i]->width == area->width) ||
+            (self->original[i]->width <= self->original[i]->height &&
+             self->original[i]->height == area->height))
         {
             pic = self->original[i];
             break;
@@ -365,8 +419,10 @@ void RrImageDrawImage(RrPixel32 *target, RrTextureImage *img,
 
     /* is there a resize of this size? */
     for (i = 0; i < self->n_resized; ++i)
-        if (self->resized[i]->width == area->width ||
-            self->resized[i]->height == area->height)
+        if ((self->resized[i]->width >= self->resized[i]->height &&
+             self->resized[i]->width == area->width) ||
+            (self->resized[i]->width <= self->resized[i]->height &&
+             self->resized[i]->height == area->height))
         {
             gint j;
             RrImagePic *saved;
@@ -431,13 +487,15 @@ void RrImageDrawImage(RrPixel32 *target, RrTextureImage *img,
 
         /* add the resized image to the image, as the first in the resized
            list */
-        if (self->n_resized >= MAX_CACHE_RESIZED) {
+        if (self->n_resized >= self->cache->max_resized_saved)
             /* remove the last one (last used one) */
             RemovePicture(self, &self->resized, self->n_resized - 1,
                           &self->n_resized);
-        }
-        /* add it to the top of the resized list */
-        AddPicture(self, &self->resized, &self->n_resized, pic);
+        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);
@@ -445,4 +503,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);
 }
This page took 0.031097 seconds and 4 git commands to generate.