diff options
Diffstat (limited to 'android/skin/image.c')
-rw-r--r-- | android/skin/image.c | 742 |
1 files changed, 0 insertions, 742 deletions
diff --git a/android/skin/image.c b/android/skin/image.c deleted file mode 100644 index 051fc6d..0000000 --- a/android/skin/image.c +++ /dev/null @@ -1,742 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** 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. -*/ -#include "android/skin/image.h" -#include "android/resource.h" -#include <assert.h> -#include <limits.h> - -#define DEBUG 0 - -#if DEBUG -static void D(const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); -} -#else -#define D(...) do{}while(0) -#endif - -/********************************************************************************/ -/********************************************************************************/ -/***** *****/ -/***** U T I L I T Y F U N C T I O N S *****/ -/***** *****/ -/********************************************************************************/ -/********************************************************************************/ - -SDL_Surface* -sdl_surface_from_argb32( void* base, int w, int h ) -{ - return SDL_CreateRGBSurfaceFrom( - base, w, h, 32, w*4, -#if WORDS_BIGENDIAN - 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 -#else - 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 -#endif - ); -} - -static void* -rotate_image( void* data, unsigned width, unsigned height, SkinRotation rotation ) -{ - void* result; - - result = malloc( width*height*4 ); - if (result == NULL) - return NULL; - - switch (rotation & 3) - { - case SKIN_ROTATION_0: - memcpy( (char*)result, (const char*)data, width*height*4 ); - break; - - case SKIN_ROTATION_270: - { - unsigned* start = (unsigned*)data; - unsigned* src_line = start + (width-1); - unsigned* dst_line = (unsigned*)result; - unsigned hh; - - for (hh = width; hh > 0; hh--) - { - unsigned* src = src_line; - unsigned* dst = dst_line; - unsigned count = height; - - for ( ; count > 0; count-- ) { - dst[0] = src[0]; - dst += 1; - src += width; - } - - src_line -= 1; - dst_line += height; - } - } - break; - - case SKIN_ROTATION_180: - { - unsigned* start = (unsigned*)data; - unsigned* src_line = start + width*(height-1); - unsigned* dst_line = (unsigned*)result; - unsigned hh; - - for (hh = height; hh > 0; hh--) - { - unsigned* src = src_line + (width-1); - unsigned* dst = dst_line; - - while (src >= src_line) - *dst++ = *src--; - - dst_line += width; - src_line -= width; - } - } - break; - - case SKIN_ROTATION_90: - { - unsigned* start = (unsigned*)data; - unsigned* src_line = start + width*(height-1); - unsigned* dst_line = (unsigned*)result ; - unsigned hh; - - for (hh = width; hh > 0; hh--) - { - unsigned* src = src_line; - unsigned* dst = dst_line; - unsigned count; - - for (count = height; count > 0; count--) { - dst[0] = src[0]; - dst += 1; - src -= width; - } - - dst_line += height; - src_line += 1; - } - } - break; - - default: - ; - } - - return result; -} - - -static void -blend_image( unsigned* dst_pixels, - unsigned* src_pixels, - unsigned w, - unsigned h, - int alpha ) -{ - unsigned* dst = dst_pixels; - unsigned* dst_end = dst + w*h; - unsigned* src = src_pixels; - - for ( ; dst < dst_end; dst++, src++ ) - { - { - unsigned ag = (src[0] >> 8) & 0xff00ff; - unsigned rb = src[0] & 0xff00ff; - - ag = (ag*alpha) & 0xff00ff00; - rb = ((rb*alpha) >> 8) & 0x00ff00ff; - - dst[0] = ag | rb; - } - } -} - - -static unsigned -skin_image_desc_hash( SkinImageDesc* desc ) -{ - unsigned h = 0; - int n; - - for (n = 0; desc->path[n] != 0; n++) { - int c = desc->path[n]; - h = h*33 + c; - } - h += desc->rotation*1573; - h += desc->blend * 7; - - return h; -} - - -static int -skin_image_desc_equal( SkinImageDesc* a, - SkinImageDesc* b ) -{ - return (a->rotation == b->rotation && - a->blend == b->blend && - !strcmp(a->path, b->path)); -} - -/********************************************************************************/ -/********************************************************************************/ -/***** *****/ -/***** S K I N I M A G E S *****/ -/***** *****/ -/********************************************************************************/ -/********************************************************************************/ - -enum { - SKIN_IMAGE_CLONE = (1 << 0) /* this image is a clone */ -}; - -struct SkinImage { - unsigned hash; - SkinImage* link; - int ref_count; - SkinImage* next; - SkinImage* prev; - SDL_Surface* surface; - unsigned flags; - unsigned w, h; - void* pixels; /* 32-bit ARGB */ - SkinImageDesc desc; -}; - - - - -static const SkinImage _no_image[1] = { - { 0, NULL, 0, NULL, NULL, NULL, 0, 0, 0, NULL, { "<none>", SKIN_ROTATION_0, 0 } } -}; - -SkinImage* SKIN_IMAGE_NONE = (SkinImage*)&_no_image; - -static void -skin_image_free( SkinImage* image ) -{ - if (image && image != _no_image) - { - if (image->surface) { - SDL_FreeSurface(image->surface); - image->surface = NULL; - } - - if (image->pixels) { - free( image->pixels ); - image->pixels = NULL; - } - - free(image); - } -} - - -static SkinImage* -skin_image_alloc( SkinImageDesc* desc, unsigned hash ) -{ - int len = strlen(desc->path); - SkinImage* image = calloc(1, sizeof(*image) + len + 1); - - if (image) { - image->desc = desc[0]; - image->desc.path = (const char*)(image + 1); - memcpy( (char*)image->desc.path, desc->path, len ); - ((char*)image->desc.path)[len] = 0; - - image->hash = hash; - image->next = image->prev = image; - image->ref_count = 1; - } - return image; -} - - -extern void *loadpng(const char *fn, unsigned *_width, unsigned *_height); -extern void *readpng(const unsigned char* base, size_t size, unsigned *_width, unsigned *_height); - -static int -skin_image_load( SkinImage* image ) -{ - void* data; - unsigned w, h; - const char* path = image->desc.path; - - if (path[0] == ':') { - size_t size; - const unsigned char* base; - - if (path[1] == '/' || path[1] == '\\') - path += 1; - - base = android_resource_find( path+1, &size ); - if (base == NULL) { - fprintf(stderr, "failed to locate built-in image file '%s'\n", path ); - return -1; - } - - data = readpng(base, size, &w, &h); - if (data == NULL) { - fprintf(stderr, "failed to load built-in image file '%s'\n", path ); - return -1; - } - } else { - data = loadpng(path, &w, &h); - if (data == NULL) { - fprintf(stderr, "failed to load image file '%s'\n", path ); - return -1; - } - } - - /* the data is loaded into memory as RGBA bytes by libpng. we want to manage - * the values as 32-bit ARGB pixels, so swap the bytes accordingly depending - * on our CPU endianess - */ - { - unsigned* d = data; - unsigned* d_end = d + w*h; - - for ( ; d < d_end; d++ ) { - unsigned pix = d[0]; -#if WORDS_BIGENDIAN - /* R,G,B,A read as RGBA => ARGB */ - pix = ((pix >> 8) & 0xffffff) | (pix << 24); -#else - /* R,G,B,A read as ABGR => ARGB */ - pix = (pix & 0xff00ff00) | ((pix >> 16) & 0xff) | ((pix & 0xff) << 16); -#endif - d[0] = pix; - } - } - - image->pixels = data; - image->w = w; - image->h = h; - - image->surface = sdl_surface_from_argb32( image->pixels, w, h ); - if (image->surface == NULL) { - fprintf(stderr, "failed to create SDL surface for '%s' image\n", path); - return -1; - } - return 0; -} - - -/* simple hash table for images */ - -#define NUM_BUCKETS 64 - -typedef struct { - SkinImage* buckets[ NUM_BUCKETS ]; - SkinImage mru_head; - int num_images; - unsigned long total_pixels; - unsigned long max_pixels; - unsigned long total_images; -} SkinImageCache; - - -static void -skin_image_cache_init( SkinImageCache* cache ) -{ - memset(cache, 0, sizeof(*cache)); -#if DEBUG - cache->max_pixels = 1; -#else - cache->max_pixels = 4*1024*1024; /* limit image cache to 4 MB */ -#endif - cache->mru_head.next = cache->mru_head.prev = &cache->mru_head; -} - - -static void -skin_image_cache_remove( SkinImageCache* cache, - SkinImage* image ) -{ - /* remove from hash table */ - SkinImage** pnode = cache->buckets + (image->hash & (NUM_BUCKETS-1)); - SkinImage* node; - - for (;;) { - node = *pnode; - assert(node != NULL); - if (node == NULL) /* should not happen */ - break; - if (node == image) { - *pnode = node->link; - break; - } - pnode = &node->link; - } - - D( "skin_image_cache: remove '%s' (rot=%d), %d pixels\n", - node->desc.path, node->desc.rotation, node->w*node->h ); - - /* remove from mru list */ - image->prev->next = image->next; - image->next->prev = image->prev; - - cache->total_pixels -= image->w*image->h; - cache->total_images -= 1; -} - - -static SkinImage* -skin_image_cache_raise( SkinImageCache* cache, - SkinImage* image ) -{ - if (image != cache->mru_head.next) { - SkinImage* prev = image->prev; - SkinImage* next = image->next; - - /* remove from mru list */ - prev->next = next; - next->prev = prev; - - /* add to top */ - image->prev = &cache->mru_head; - image->next = image->prev->next; - image->prev->next = image; - image->next->prev = image; - } - return image; -} - - -static void -skin_image_cache_flush( SkinImageCache* cache ) -{ - SkinImage* image = cache->mru_head.prev; - int count = 0; - - D("skin_image_cache_flush: starting\n"); - while (cache->total_pixels > cache->max_pixels && - image != &cache->mru_head) - { - SkinImage* prev = image->prev; - - if (image->ref_count == 0) { - skin_image_cache_remove(cache, image); - count += 1; - } - image = prev; - } - D("skin_image_cache_flush: finished, %d images flushed\n", count); -} - - -static SkinImage** -skin_image_lookup_p( SkinImageCache* cache, - SkinImageDesc* desc, - unsigned *phash ) -{ - unsigned h = skin_image_desc_hash(desc); - unsigned index = h & (NUM_BUCKETS-1); - SkinImage** pnode = &cache->buckets[index]; - for (;;) { - SkinImage* node = *pnode; - if (node == NULL) - break; - if (node->hash == h && skin_image_desc_equal(desc, &node->desc)) - break; - pnode = &node->link; - } - *phash = h; - return pnode; -} - - -static SkinImage* -skin_image_create( SkinImageDesc* desc, unsigned hash ) -{ - SkinImage* node; - - node = skin_image_alloc( desc, hash ); - if (node == NULL) - return SKIN_IMAGE_NONE; - - if (desc->rotation == SKIN_ROTATION_0 && - desc->blend == SKIN_BLEND_FULL) - { - if (skin_image_load(node) < 0) { - skin_image_free(node); - return SKIN_IMAGE_NONE; - } - } - else - { - SkinImageDesc desc0 = desc[0]; - SkinImage* parent; - - desc0.rotation = SKIN_ROTATION_0; - desc0.blend = SKIN_BLEND_FULL; - - parent = skin_image_find( &desc0 ); - if (parent == SKIN_IMAGE_NONE) - return SKIN_IMAGE_NONE; - - SDL_LockSurface(parent->surface); - - if (desc->rotation == SKIN_ROTATION_90 || - desc->rotation == SKIN_ROTATION_270) - { - node->w = parent->h; - node->h = parent->w; - } else { - node->w = parent->w; - node->h = parent->h; - } - - node->pixels = rotate_image( parent->pixels, parent->w, parent->h, - desc->rotation ); - - SDL_UnlockSurface(parent->surface); - skin_image_unref(&parent); - - if (node->pixels == NULL) { - skin_image_free(node); - return SKIN_IMAGE_NONE; - } - - if (desc->blend != SKIN_BLEND_FULL) - blend_image( node->pixels, node->pixels, node->w, node->h, desc->blend ); - - node->surface = sdl_surface_from_argb32( node->pixels, node->w, node->h ); - if (node->surface == NULL) { - skin_image_free(node); - return SKIN_IMAGE_NONE; - } - } - return node; -} - - -static SkinImageCache _image_cache[1]; -static int _image_cache_init; - -SkinImage* -skin_image_find( SkinImageDesc* desc ) -{ - SkinImageCache* cache = _image_cache; - unsigned hash; - SkinImage** pnode = skin_image_lookup_p( cache, desc, &hash ); - SkinImage* node = *pnode; - - if (!_image_cache_init) { - _image_cache_init = 1; - skin_image_cache_init(cache); - } - - if (node) { - node->ref_count += 1; - return skin_image_cache_raise( cache, node ); - } - node = skin_image_create( desc, hash ); - if (node == SKIN_IMAGE_NONE) - return node; - - /* add to hash table */ - node->link = *pnode; - *pnode = node; - - /* add to mru list */ - skin_image_cache_raise( cache, node ); - - D( "skin_image_cache: add '%s' (rot=%d), %d pixels\n", - node->desc.path, node->desc.rotation, node->w*node->h ); - - cache->total_pixels += node->w*node->h; - if (cache->total_pixels > cache->max_pixels) - skin_image_cache_flush( cache ); - - return node; -} - - -SkinImage* -skin_image_find_simple( const char* path ) -{ - SkinImageDesc desc; - - desc.path = path; - desc.rotation = SKIN_ROTATION_0; - desc.blend = SKIN_BLEND_FULL; - - return skin_image_find( &desc ); -} - - -SkinImage* -skin_image_ref( SkinImage* image ) -{ - if (image && image != _no_image) - image->ref_count += 1; - - return image; -} - - -void -skin_image_unref( SkinImage** pimage ) -{ - SkinImage* image = *pimage; - - if (image) { - if (image != _no_image && --image->ref_count == 0) { - if ((image->flags & SKIN_IMAGE_CLONE) != 0) { - skin_image_free(image); - } - } - *pimage = NULL; - } -} - - -SkinImage* -skin_image_rotate( SkinImage* source, SkinRotation rotation ) -{ - SkinImageDesc desc; - SkinImage* image; - - if (source == _no_image || source->desc.rotation == rotation) - return source; - - desc = source->desc; - desc.rotation = rotation; - image = skin_image_find( &desc ); - skin_image_unref( &source ); - return image; -} - - -SkinImage* -skin_image_clone( SkinImage* source ) -{ - SkinImage* image; - - if (source == NULL || source == _no_image) - return SKIN_IMAGE_NONE; - - image = calloc(1,sizeof(*image)); - if (image == NULL) - goto Fail; - - image->desc = source->desc; - image->hash = source->hash; - image->flags = SKIN_IMAGE_CLONE; - image->w = source->w; - image->h = source->h; - image->pixels = rotate_image( source->pixels, source->w, source->h, - SKIN_ROTATION_0 ); - if (image->pixels == NULL) - goto Fail; - - image->surface = sdl_surface_from_argb32( image->pixels, image->w, image->h ); - if (image->surface == NULL) - goto Fail; - - return image; -Fail: - if (image != NULL) - skin_image_free(image); - return SKIN_IMAGE_NONE; -} - -SkinImage* -skin_image_clone_full( SkinImage* source, - SkinRotation rotation, - int blend ) -{ - SkinImageDesc desc; - SkinImage* clone; - - if (source == NULL || source == SKIN_IMAGE_NONE) - return SKIN_IMAGE_NONE; - - if (rotation == SKIN_ROTATION_0 && - blend == SKIN_BLEND_FULL) - { - return skin_image_clone(source); - } - - desc.path = source->desc.path; - desc.rotation = rotation; - desc.blend = blend; - - clone = skin_image_create( &desc, 0 ); - if (clone != SKIN_IMAGE_NONE) - clone->flags |= SKIN_IMAGE_CLONE; - - return clone; -} - -/* apply blending to a source skin image and copy the result to a target clone image */ -extern void -skin_image_blend_clone( SkinImage* clone, SkinImage* source, int blend ) -{ - SDL_LockSurface( clone->surface ); - blend_image( clone->pixels, source->pixels, source->w, source->h, blend ); - SDL_UnlockSurface( clone->surface ); - SDL_SetAlpha( clone->surface, SDL_SRCALPHA, 255 ); -} - -int -skin_image_w( SkinImage* image ) -{ - return image ? image->w : 0; -} - -int -skin_image_h( SkinImage* image ) -{ - return image ? image->h : 0; -} - -int -skin_image_org_w( SkinImage* image ) -{ - if (image) { - if (image->desc.rotation == SKIN_ROTATION_90 || - image->desc.rotation == SKIN_ROTATION_270) - return image->h; - else - return image->w; - } - return 0; -} - -int -skin_image_org_h( SkinImage* image ) -{ - if (image) { - if (image->desc.rotation == SKIN_ROTATION_90 || - image->desc.rotation == SKIN_ROTATION_270) - return image->w; - else - return image->h; - } - return 0; -} - -SDL_Surface* -skin_image_surface( SkinImage* image ) -{ - return image ? image->surface : NULL; -} |