diff --git a/openbox/openbox.c b/openbox/openbox.c index f2dc7159..46da8fee 100644 --- a/openbox/openbox.c +++ b/openbox/openbox.c @@ -183,7 +183,11 @@ gint main(gint argc, gchar **argv) ob_rr_inst = RrInstanceNew(ob_display, ob_screen); if (ob_rr_inst == NULL) ob_exit_with_error(_("Failed to initialize the obrender library.")); - ob_rr_icons = RrImageCacheNew(); + /* Saving 3 resizes of an RrImage makes a lot of sense for icons, as there + are generally 3 icon sizes needed: the titlebar icon, the menu icon, + and the alt-tab icon + */ + ob_rr_icons = RrImageCacheNew(3); XSynchronize(ob_display, xsync); diff --git a/render/image.c b/render/image.c index 8ce3a57c..a618f782 100644 --- a/render/image.c +++ b/render/image.c @@ -28,6 +28,9 @@ #define FLOOR(i) ((i) & (~0UL << FRACTION)) #define AVERAGE(a, b) (((((a) ^ (b)) & 0xfefefefeL) >> 1) + ((a) & (b))) +/*! 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) { @@ -58,6 +61,8 @@ static void AddPicture(RrImage *self, RrImagePic ***list, gint *len, #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) { @@ -84,9 +89,14 @@ 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; RrImagePic *pic; @@ -199,6 +209,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 +258,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) @@ -270,10 +283,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; @@ -300,6 +316,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; @@ -330,6 +349,9 @@ void RrImageAddPicture(RrImage *self, RrPixel32 *data, gint w, gint h) 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 +364,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) @@ -431,13 +458,13 @@ 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); } g_assert(pic != NULL); diff --git a/render/imagecache.c b/render/imagecache.c index ec2ff4d0..9ebaec13 100644 --- a/render/imagecache.c +++ b/render/imagecache.c @@ -22,12 +22,15 @@ static gboolean RrImagePicEqual(const RrImagePic *p1, const RrImagePic *p2); -RrImageCache* RrImageCacheNew() +RrImageCache* RrImageCacheNew(gint max_resized_saved) { RrImageCache *self; + g_assert(max_resized_saved >= 0); + self = g_new(RrImageCache, 1); self->ref = 1; + self->max_resized_saved = max_resized_saved; self->table = g_hash_table_new((GHashFunc)RrImagePicHash, (GEqualFunc)RrImagePicEqual); return self; @@ -59,9 +62,6 @@ RrImage* RrImageCacheFind(RrImageCache *self, return g_hash_table_lookup(self->table, &pic); } -/* This is a fast, reversable hash function called "lookup3", found here: - http://burtleburtle.net/bob/c/lookup3.c -*/ #define hashsize(n) ((RrPixel32)1<<(n)) #define hashmask(n) (hashsize(n)-1) #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) @@ -87,6 +87,13 @@ RrImage* RrImageCacheFind(RrImageCache *self, c ^= b; c -= rot(b,24); \ } +/* This is a fast, reversable hash function called "lookup3", found here: + http://burtleburtle.net/bob/c/lookup3.c, by Bob Jenkins + + This hashing algorithm is "reversible", that is, not cryptographically + secure at all. But we don't care about that, we just want something to + tell when images are the same or different relatively quickly. +*/ guint32 hashword(const guint32 *key, gint length, guint32 initval) { guint32 a,b,c; @@ -119,6 +126,9 @@ guint32 hashword(const guint32 *key, gint length, guint32 initval) return c; } +/*! This is some arbitrary initial value for the hashing function. It's + constant so that you get the same result from the same data each time. +*/ #define HASH_INITVAL 0xf00d guint RrImagePicHash(const RrImagePic *p) diff --git a/render/imagecache.h b/render/imagecache.h index 8c96caf0..4ad2deae 100644 --- a/render/imagecache.h +++ b/render/imagecache.h @@ -21,15 +21,29 @@ #include -/* the number of resized pictures to cache for an image */ -#define MAX_CACHE_RESIZED 3 - struct _RrImagePic; guint RrImagePicHash(const struct _RrImagePic *p); +/*! Create a new image cache. An image cache is basically a hash table to look + up RrImages. Each RrImage in the cache may contain one or more Pictures, + that is one or more actual copies of image data at various sizes. For eg, + for a window, all of its various icons are loaded into the same RrImage. + When an RrImage is drawn and a picture inside it needs to be resized, that + is also saved within the RrImage. + + For each picture that an RrImage has, the picture is hashed and that is used + as a key to find the RrImage. So, given any picture in any RrImage in the + cache, if you hash it, you will find the RrImage. +*/ struct _RrImageCache { gint ref; + /*! When an original picture is resized for an RrImage, the resized picture + is saved in the RrImage. This specifies how many pictures should be + saved at a time. When this is exceeded, the least recently used + "resized" picture is deleted. + */ + gint max_resized_saved; GHashTable *table; }; diff --git a/render/render.h b/render/render.h index e79727df..7053664d 100644 --- a/render/render.h +++ b/render/render.h @@ -234,11 +234,18 @@ struct _RrImagePic { pictures */ struct _RrImage { gint ref; - struct _RrImageCache *cache; + RrImageCache *cache; - struct _RrImagePic **original; + /*! An array of "originals", that is of RrPictures that have been added + to the image in various sizes, and that have not been resized. These + are explicitly added to the RrImage. */ + RrImagePic **original; gint n_original; - struct _RrImagePic **resized; + /*! An array of "resized" pictures. When an "original" RrPicture + needs to be resized for drawing, it is saved in here so that it doesn't + need to be resized again. These are automatically added to the + RrImage. */ + RrImagePic **resized; gint n_resized; }; @@ -317,7 +324,10 @@ gboolean RrPixmapToRGBA(const RrInstance *inst, Pixmap pmap, Pixmap mask, gint *w, gint *h, RrPixel32 **data); -RrImageCache* RrImageCacheNew(); +/*! Create a new image cache for RrImages. + @param max_resized_saved The number of resized copies of an image to save +*/ +RrImageCache* RrImageCacheNew(gint max_resized_saved); void RrImageCacheRef(RrImageCache *self); void RrImageCacheUnref(RrImageCache *self);