Set up work for making a 3.5 prerelease.
[dana/openbox.git] / render / image.c
diff --git a/render/image.c b/render/image.c
deleted file mode 100644 (file)
index 924504f..0000000
+++ /dev/null
@@ -1,516 +0,0 @@
-/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
-
-   image.c for the Openbox window manager
-   Copyright (c) 2006        Mikael Magnusson
-   Copyright (c) 2003-2007   Dana Jansens
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   See the COPYING file for a copy of the GNU General Public License.
-*/
-
-#include "geom.h"
-#include "image.h"
-#include "color.h"
-#include "imagecache.h"
-
-#include <glib.h>
-
-#define FRACTION        12
-#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)
-{
-    gint i;
-
-    g_assert(pic->width > 0 && pic->height > 0);
-
-    g_assert(g_hash_table_lookup(self->cache->table, pic) == NULL);
-
-    /* grow the list */
-    *list = g_renew(RrImagePic*, *list, ++*len);
-
-    /* move everything else down one */
-    for (i = *len-1; i > 0; --i)
-        (*list)[i] = (*list)[i-1];
-
-    /* set the new picture up at the front of the list */
-    (*list)[0] = pic;
-
-    /* add the picture as a key to point to this image in the cache */
-    g_hash_table_insert(self->cache->table, (*list)[0], self);
-
-/*
-#ifdef DEBUG
-    g_debug("Adding %s picture to the cache:\n    "
-            "Image 0x%lx, w %d h %d Hash %u",
-            (*list == self->original ? "ORIGINAL" : "RESIZED"),
-            (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_debug("Removing %s picture from the cache:\n    "
-            "Image 0x%lx, w %d h %d Hash %u",
-            (*list == self->original ? "ORIGINAL" : "RESIZED"),
-            (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 */
-    RrImagePicFree((*list)[i]);
-    /* shift everything down one */
-    for (j = i; j < *len-1; ++j)
-        (*list)[j] = (*list)[j+1];
-    /* shrink the 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)
-{
-    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));
-    if (aspectH > dstH) {
-        aspectH = dstH;
-        aspectW = (gint)(dstH * ((gdouble)srcW / srcH));
-    }
-    dstW = aspectW ? aspectW : 1;
-    dstH = aspectH ? aspectH : 1;
-
-    if (srcW == dstW && srcH == dstH)
-        return NULL; /* no scaling needed! */
-
-    dststart = dst = g_new(RrPixel32, dstW * dstH);
-
-    ratioX = (srcW << FRACTION) / dstW;
-    ratioY = (srcH << FRACTION) / dstH;
-
-    srcY2 = 0;
-    for (dstY = 0; dstY < dstH; dstY++) {
-        srcY1 = srcY2;
-        srcY2 += ratioY;
-
-        srcX2 = 0;
-        for (dstX = 0; dstX < dstW; dstX++) {
-            gulong red = 0, green = 0, blue = 0, alpha = 0;
-            gulong portionX, portionY, portionXY, sumXY = 0;
-            RrPixel32 pixel;
-
-            srcX1 = srcX2;
-            srcX2 += ratioX;
-
-            for (srcY = srcY1; srcY < srcY2; srcY += (1UL << FRACTION)) {
-                if (srcY == srcY1) {
-                    srcY = FLOOR(srcY);
-                    portionY = (1UL << FRACTION) - (srcY1 - srcY);
-                    if (portionY > srcY2 - srcY1)
-                        portionY = srcY2 - srcY1;
-                }
-                else if (srcY == FLOOR(srcY2))
-                    portionY = srcY2 - srcY;
-                else
-                    portionY = (1UL << FRACTION);
-
-                for (srcX = srcX1; srcX < srcX2; srcX += (1UL << FRACTION)) {
-                    if (srcX == srcX1) {
-                        srcX = FLOOR(srcX);
-                        portionX = (1UL << FRACTION) - (srcX1 - srcX);
-                        if (portionX > srcX2 - srcX1)
-                            portionX = srcX2 - srcX1;
-                    }
-                    else if (srcX == FLOOR(srcX2))
-                        portionX = srcX2 - srcX;
-                    else
-                        portionX = (1UL << FRACTION);
-
-                    portionXY = (portionX * portionY) >> FRACTION;
-                    sumXY += portionXY;
-
-                    pixel = *(src + (srcY >> FRACTION) * srcW
-                            + (srcX >> FRACTION));
-                    red   += ((pixel >> RrDefaultRedOffset)   & 0xFF)
-                             * portionXY;
-                    green += ((pixel >> RrDefaultGreenOffset) & 0xFF)
-                             * portionXY;
-                    blue  += ((pixel >> RrDefaultBlueOffset)  & 0xFF)
-                             * portionXY;
-                    alpha += ((pixel >> RrDefaultAlphaOffset) & 0xFF)
-                             * portionXY;
-                }
-            }
-
-            g_assert(sumXY != 0);
-            red   /= sumXY;
-            green /= sumXY;
-            blue  /= sumXY;
-            alpha /= sumXY;
-
-            *dst++ = (red   << RrDefaultRedOffset)   |
-                     (green << RrDefaultGreenOffset) |
-                     (blue  << RrDefaultBlueOffset)  |
-                     (alpha << RrDefaultAlphaOffset);
-        }
-    }
-
-    pic = g_new(RrImagePic, 1);
-    RrImagePicInit(pic, dstW, dstH, dststart);
-
-    return pic;
-}
-
-/*! 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,
-              RrPixel32 *source, gint source_w, gint source_h,
-              gint alpha, RrRect *area)
-{
-    RrPixel32 *dest;
-    gint col, num_pixels;
-    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;
-    dh = (gint)(dw * ((gdouble)source_h / source_w));
-    if (dh > area->height) {
-        dh = area->height;
-        dw = (gint)(dh * ((gdouble)source_w / source_h));
-    }
-
-    /* copy source -> dest, and apply the alpha channel.
-       center the image if it is smaller than the area */
-    col = 0;
-    num_pixels = dw * dh;
-    dest = target + area->x + (area->width - dw) / 2 +
-        (target_w * (area->y + (area->height - dh) / 2));
-    while (num_pixels-- > 0) {
-        guchar a, r, g, b, bgr, bgg, bgb;
-
-        /* apply the rgba's opacity as well */
-        a = ((*source >> RrDefaultAlphaOffset) * alpha) >> 8;
-        r = *source >> RrDefaultRedOffset;
-        g = *source >> RrDefaultGreenOffset;
-        b = *source >> RrDefaultBlueOffset;
-
-        /* background color */
-        bgr = *dest >> RrDefaultRedOffset;
-        bgg = *dest >> RrDefaultGreenOffset;
-        bgb = *dest >> RrDefaultBlueOffset;
-
-        r = bgr + (((r - bgr) * a) >> 8);
-        g = bgg + (((g - bgg) * a) >> 8);
-        b = bgb + (((b - bgb) * a) >> 8);
-
-        *dest = ((r << RrDefaultRedOffset) |
-                 (g << RrDefaultGreenOffset) |
-                 (b << RrDefaultBlueOffset));
-
-        dest++;
-        source++;
-
-        if (++col >= dw) {
-            col = 0;
-            dest += target_w - dw;
-        }
-    }
-}
-
-/*! Draw an RGBA texture into a target pixel buffer. */
-void RrImageDrawRGBA(RrPixel32 *target, RrTextureRGBA *rgba,
-                     gint target_w, gint target_h,
-                     RrRect *area)
-{
-    RrImagePic *scaled;
-
-    scaled = ResizeImage(rgba->data, rgba->width, rgba->height,
-                         area->width, area->height);
-
-    if (scaled) {
-#ifdef DEBUG
-            g_warning("Scaling an RGBA! You should avoid this and just make "
-                      "it the right size yourself!");
-#endif
-            DrawRGBA(target, target_w, target_h,
-                     scaled->data, scaled->width, scaled->height,
-                     rgba->alpha, area);
-            RrImagePicFree(scaled);
-    }
-    else
-        DrawRGBA(target, target_w, target_h,
-                 rgba->data, rgba->width, rgba->height,
-                 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;
-    return self;
-}
-
-void RrImageRef(RrImage *self)
-{
-    ++self->ref;
-}
-
-void RrImageUnref(RrImage *self)
-{
-    if (self && --self->ref == 0) {
-/*
-#ifdef DEBUG
-        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);
-        while (self->n_resized > 0)
-            RemovePicture(self, &self->resized, 0, &self->n_resized);
-        g_free(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;
-    RrImagePic *pic;
-
-    /* make sure we don't already have this size.. */
-    for (i = 0; i < self->n_original; ++i)
-        if (self->original[i]->width == w && self->original[i]->height == h) {
-/*
-#ifdef DEBUG
-            g_debug("Found duplicate ORIGINAL image:\n    "
-                    "Image 0x%lx, w %d h %d", (gulong)self, w, h);
-#endif
-*/
-            return;
-        }
-
-    /* remove any resized pictures of this same size */
-    for (i = 0; i < self->n_resized; ++i)
-        if (self->resized[i]->width == w || self->resized[i]->height == h) {
-            RemovePicture(self, &self->resized, i, &self->n_resized);
-            break;
-        }
-
-    /* add the new picture */
-    pic = g_new(RrImagePic, 1);
-    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;
-
-    /* remove any resized pictures of this same size */
-    for (i = 0; i < self->n_original; ++i)
-        if (self->original[i]->width == w && self->original[i]->height == h) {
-            RemovePicture(self, &self->original, i, &self->n_original);
-            break;
-        }
-}
-
-/*! 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)
-{
-    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 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 >= 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;
-        }
-
-    /* is there a resize of this size? */
-    for (i = 0; i < self->n_resized; ++i)
-        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;
-
-            /* save the selected one */
-            saved = self->resized[i];
-
-            /* shift all the others down */
-            for (j = i; j > 0; --j)
-                self->resized[j] = self->resized[j-1];
-
-            /* and move the selected one to the top of the list */
-            self->resized[0] = saved;
-
-            pic = self->resized[0];
-            break;
-        }
-
-    if (!pic) {
-        gdouble aspect;
-
-        /* find an original with a close size */
-        min_diff = min_aspect_diff = -1;
-        min_i = min_aspect_i = 0;
-        aspect = ((gdouble)area->width) / area->height;
-        for (i = 0; i < self->n_original; ++i) {
-            gint diff;
-            gint wdiff, hdiff;
-            gdouble myasp;
-
-            /* our size difference metric.. */
-            wdiff = self->original[i]->width - area->width;
-            hdiff = self->original[i]->height - area->height;
-            diff = (wdiff * wdiff) + (hdiff * hdiff);
-
-            /* find the smallest difference */
-            if (min_diff < 0 || diff < min_diff) {
-                min_diff = diff;
-                min_i = i;
-            }
-            /* and also find the smallest difference with the same aspect
-               ratio (and prefer this one) */
-            myasp = ((gdouble)self->original[i]->width) /
-                self->original[i]->height;
-            if (ABS(aspect - myasp) < 0.0000001 &&
-                (min_aspect_diff < 0 || diff < min_aspect_diff))
-            {
-                min_aspect_diff = diff;
-                min_aspect_i = i;
-            }
-        }
-
-        /* use the aspect ratio correct source if there is one */
-        if (min_aspect_i >= 0)
-            min_i = min_aspect_i;
-
-        /* resize the original to the given area */
-        pic = ResizeImage(self->original[min_i]->data,
-                          self->original[min_i]->width,
-                          self->original[min_i]->height,
-                          area->width, area->height);
-
-        /* add the resized image to the image, as the first in the resized
-           list */
-        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);
-        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);
-
-    DrawRGBA(target, target_w, target_h,
-             pic->data, pic->width, pic->height,
-             img->alpha, area);
-    if (free_pic)
-        RrImagePicFree(pic);
-}