#include "evas_common_soft8.h" static Evas_Cache_Image *eci = NULL; static int reference = 0; static Image_Entry *_evas_common_soft8_image_new(void); static void _evas_common_soft8_image_delete(Image_Entry * ie); static int _evas_common_soft8_image_surface_alloc(Image_Entry * ie, unsigned int w, unsigned int h); static void _evas_common_soft8_image_surface_delete(Image_Entry * ie); static DATA32 *_evas_common_soft8_image_surface_pixels(Image_Entry * ie); static int _evas_common_load_soft8_image_from_file(Image_Entry * ie); static void _evas_common_soft8_image_unload(Image_Entry * ie); static void _evas_common_soft8_image_dirty_region(Image_Entry * im, unsigned int x, unsigned int y, unsigned int w, unsigned int h); static int _evas_common_soft8_image_dirty(Image_Entry * ie_dst, const Image_Entry * ie_src); static int _evas_common_soft8_image_ram_usage(Image_Entry * ie); static int _evas_common_soft8_image_size_set(Image_Entry * ie_dst, const Image_Entry * ie_im, unsigned int w, unsigned int h); static int _evas_common_soft8_image_from_copied_data(Image_Entry * ie_dst, unsigned int w, unsigned int h, DATA32 * image_data, int alpha, int cspace); static int _evas_common_soft8_image_from_data(Image_Entry * ie_dst, unsigned int w, unsigned int h, DATA32 * image_data, int alpha, int cspace); static int _evas_common_soft8_image_colorspace_set(Image_Entry * ie_dst, int cspace); static int _evas_common_load_soft8_image_data_from_file(Image_Entry * ie); /* static void _evas_common_soft8_image_debug(const char* context, Image_Entry *eim) { DBG("[8] %p = [%s] {%s,%s} %i [%i|%i]", eim, context, eim->file, eim->key, eim->references, eim->w, eim->h); } */ static const Evas_Cache_Image_Func _evas_common_soft8_image_func = { _evas_common_soft8_image_new, _evas_common_soft8_image_delete, _evas_common_soft8_image_surface_alloc, _evas_common_soft8_image_surface_delete, _evas_common_soft8_image_surface_pixels, _evas_common_load_soft8_image_from_file, _evas_common_soft8_image_unload, _evas_common_soft8_image_dirty_region, _evas_common_soft8_image_dirty, _evas_common_soft8_image_size_set, _evas_common_soft8_image_from_copied_data, _evas_common_soft8_image_from_data, _evas_common_soft8_image_colorspace_set, _evas_common_load_soft8_image_data_from_file, _evas_common_soft8_image_ram_usage, /* _evas_common_soft8_image_debug */ NULL }; EAPI void evas_common_soft8_image_init(void) { if (!eci) eci = evas_cache_image_init(&_evas_common_soft8_image_func); reference++; } EAPI void evas_common_soft8_image_shutdown(void) { if (--reference == 0) { // DISABLE for now - something wrong with cache shutdown freeing things // still in use - rage_thumb segv's now. // // actually - i think i see it. cache ref goes to 0 (and thus gets freed) // because in eng_setup() when a buffer changes size it is FIRST freed // THEN allocated again - thus brignhjing ref to 0 then back to 1 immediately // where it should stay at 1. - see evas_engine.c in the buffer enigne for // example. eng_output_free() is called BEFORE _output_setup(). although this // is only a SIGNE of the problem. we can patch this up with either freeing // after the setup (so we just pt a ref of 2 then back to 1), or just // evas_common_image_init() at the start and evas_common_image_shutdown() // after it all. really ref 0 should only be reached when no more canvases // with no more objects exist anywhere. // ENABLE IT AGAIN, hope it is fixed. Gustavo @ January 22nd, 2009. //evas_cache_image_shutdown(eci); //eci = NULL; } } EAPI Evas_Cache_Image * evas_common_soft8_image_cache_get(void) { return eci; } static Image_Entry * _evas_common_soft8_image_new(void) { Soft8_Image *im; im = calloc(1, sizeof(Soft8_Image)); if (!im) return NULL; im->stride = -1; return (Image_Entry *) im; } static void _evas_common_soft8_image_delete(Image_Entry * ie) { memset(ie, 0xFF, sizeof(Soft8_Image)); free(ie); } static int _evas_common_soft8_image_surface_alloc(Image_Entry * ie, unsigned int w, unsigned int h) { Soft8_Image *im = (Soft8_Image *) ie; if (im->stride < 0) im->stride = _calc_stride(w); im->pixels = realloc(im->pixels, IMG_BYTE_SIZE(im->stride, h, ie->flags.alpha)); if (!im->pixels) return -1; if (ie->flags.alpha) { im->alpha = (DATA8 *) (im->pixels + (im->stride * h)); im->flags.free_alpha = 0; } im->flags.free_pixels = 1; return 0; } static void _evas_common_soft8_image_surface_delete(Image_Entry * ie) { Soft8_Image *im = (Soft8_Image *) ie; if (im->flags.free_pixels) free(im->pixels); im->pixels = NULL; im->flags.free_pixels = 0; if (im->flags.free_alpha) free(im->alpha); im->alpha = NULL; im->flags.free_alpha = 0; } static DATA32 * _evas_common_soft8_image_surface_pixels(Image_Entry * ie __UNUSED__) { abort(); return NULL; } static int _evas_common_load_soft8_image_from_file(Image_Entry * ie) { Soft8_Image *sim = (Soft8_Image *) ie; RGBA_Image *im; int error = 0; im = (RGBA_Image *) evas_cache_image_request(evas_common_image_cache_get(), sim->cache_entry.file, sim->cache_entry.key, &sim->cache_entry.load_opts, &error); sim->source = im; if (!sim->source) return -1; sim->cache_entry.w = sim->source->cache_entry.w; sim->cache_entry.h = sim->source->cache_entry.h; ie->flags.alpha = im->cache_entry.flags.alpha; if (sim->stride < 0) sim->stride = _calc_stride(sim->cache_entry.w); return 0; } static void _evas_common_soft8_image_unload(Image_Entry * ie __UNUSED__) { } static void _evas_common_soft8_image_dirty_region(Image_Entry * im __UNUSED__, unsigned int x __UNUSED__, unsigned int y __UNUSED__, unsigned int w __UNUSED__, unsigned int h __UNUSED__) { } static int _evas_common_soft8_image_dirty(Image_Entry * ie_dst, const Image_Entry * ie_src) { Soft8_Image *dst = (Soft8_Image *) ie_dst; Soft8_Image *src = (Soft8_Image *) ie_src; evas_cache_image_load_data(&src->cache_entry); evas_cache_image_surface_alloc(&dst->cache_entry, src->cache_entry.w, src->cache_entry.h); /* evas_common_blit_rectangle(src, dst, 0, 0, src->cache_entry.w, src->cache_entry.h, 0, 0); */ return 0; } static int _evas_common_soft8_image_ram_usage(Image_Entry * ie) { Soft8_Image *im = (Soft8_Image *) ie; if (im->pixels && im->flags.free_pixels) return IMG_BYTE_SIZE(im->stride, im->cache_entry.h, ie->flags.alpha); return 0; } static int _evas_common_soft8_image_size_set(Image_Entry * ie_dst, const Image_Entry * ie_im, unsigned int w __UNUSED__, unsigned int h __UNUSED__) { Soft8_Image *dst = (Soft8_Image *) ie_dst; Soft8_Image *im = (Soft8_Image *) ie_im; dst->flags = im->flags; return 0; } static int _evas_common_soft8_image_from_data(Image_Entry * ie_dst, unsigned int w, unsigned int h, DATA32 * image_data, int alpha, int cspace __UNUSED__) { Soft8_Image *im = (Soft8_Image *) ie_dst; /* FIXME: handle colorspace */ ie_dst->w = w; ie_dst->h = h; ie_dst->flags.alpha = alpha; im->flags.free_pixels = 0; im->flags.free_alpha = 0; if (im->stride < 0) im->stride = _calc_stride(w); /* FIXME: That's bad, the application must be aware of the engine internal. */ im->pixels = (DATA8 *) image_data; if (ie_dst->flags.alpha) im->alpha = (DATA8 *) (im->pixels + (im->stride * h)); return 0; } static int _evas_common_soft8_image_from_copied_data(Image_Entry * ie_dst, unsigned int w __UNUSED__, unsigned int h, DATA32 * image_data, int alpha __UNUSED__, int cspace __UNUSED__) { Soft8_Image *im = (Soft8_Image *) ie_dst; /* FIXME: handle colorspace */ if (image_data) memcpy(im->pixels, image_data, IMG_BYTE_SIZE(im->stride, h, ie_dst->flags.alpha)); else memset(im->pixels, 0, IMG_BYTE_SIZE(im->stride, h, ie_dst->flags.alpha)); return 0; } static int _evas_common_soft8_image_colorspace_set(Image_Entry * ie_dst __UNUSED__, int cspace __UNUSED__) { /* FIXME: handle colorspace */ return 0; } static int _evas_common_load_soft8_image_data_from_file(Image_Entry * ie) { Soft8_Image *im = (Soft8_Image *) ie; if (im->pixels) return 0; if (!im->source) return -1; evas_cache_image_load_data(&im->source->cache_entry); if (im->source->image.data) { DATA32 *sp; evas_cache_image_surface_alloc(&im->cache_entry, im->source->cache_entry.w, im->source->cache_entry.h); sp = im->source->image.data; if (im->alpha) evas_common_soft8_image_convert_from_rgba(im, sp); else evas_common_soft8_image_convert_from_rgb(im, sp); } evas_cache_image_drop(&im->source->cache_entry); im->source = NULL; return 0; } /* Soft16_Image * */ /* evas_common_soft16_image_new(int w, unsigned int h, unsigned int stride, int have_alpha, DATA16 *pixels, */ /* int copy) */ /* { */ /* Soft16_Image *im; */ /* if (stride < 0) stride = _calc_stride(w); */ /* im = evas_common_soft16_image_alloc(w, h, stride, have_alpha, copy); */ /* if (!im) return NULL; */ /* if (pixels) */ /* { */ /* if (copy) */ /* memcpy(im->pixels, pixels, IMG_BYTE_SIZE(stride, h, have_alpha)); */ /* else */ /* { */ /* im->pixels = pixels; */ /* if (have_alpha) im->alpha = (DATA8 *)(im->pixels + (stride * h)); */ /* } */ /* } */ /* return im; */ /* } */ static inline void _get_clip(const RGBA_Draw_Context * dc, const Soft8_Image * im, Eina_Rectangle * clip) { if (dc->clip.use) { EINA_RECTANGLE_SET(clip, dc->clip.x, dc->clip.y, dc->clip.w, dc->clip.h); if (clip->x < 0) { clip->w += clip->x; clip->x = 0; } if (clip->y < 0) { clip->h += clip->y; clip->y = 0; } if ((clip->x + clip->w) > (int)im->cache_entry.w) clip->w = im->cache_entry.w - clip->x; if ((clip->y + clip->h) > (int)im->cache_entry.h) clip->h = im->cache_entry.h - clip->y; } else { EINA_RECTANGLE_SET(clip, 0, 0, im->cache_entry.w, im->cache_entry.h); } } static inline int _is_empty_rectangle(const Eina_Rectangle * r) { return (r->w < 1) || (r->h < 1); } static inline void _shrink(int *s_pos, int *s_size, int pos, int size) { int d; d = (*s_pos) - pos; if (d < 0) { (*s_size) += d; (*s_pos) = pos; } d = size + pos - (*s_pos); if ((*s_size) > d) (*s_size) = d; } static int _soft8_adjust_areas(Eina_Rectangle * src, int src_max_x, int src_max_y, Eina_Rectangle * dst, int dst_max_x, int dst_max_y, Eina_Rectangle * dst_clip) { if (_is_empty_rectangle(src) || _is_empty_rectangle(dst) || _is_empty_rectangle(dst_clip)) return 0; /* shrink clip */ _shrink(&dst_clip->x, &dst_clip->w, dst->x, dst->w); _shrink(&dst_clip->y, &dst_clip->h, dst->y, dst->h); if (_is_empty_rectangle(dst_clip)) return 0; /* sanitise x */ if (src->x < 0) { dst->x -= (src->x * dst->w) / src->w; dst->w += (src->x * dst->w) / src->w; src->w += src->x; src->x = 0; } if (src->x >= src_max_x) return 0; if ((src->x + src->w) > src_max_x) { dst->w = (dst->w * (src_max_x - src->x)) / (src->w); src->w = src_max_x - src->x; } if (dst->w <= 0) return 0; if (src->w <= 0) return 0; if (dst_clip->x < 0) { dst_clip->w += dst_clip->x; dst_clip->x = 0; } if (dst_clip->w <= 0) return 0; if (dst_clip->x >= dst_max_x) return 0; _shrink(&dst_clip->x, &dst_clip->w, 0, dst_max_x); if (dst_clip->w <= 0) return 0; /* sanitise y */ if (src->y < 0) { dst->y -= (src->y * dst->h) / src->h; dst->h += (src->y * dst->h) / src->h; src->h += src->y; src->y = 0; } if (src->y >= src_max_y) return 0; if ((src->y + src->h) > src_max_y) { dst->h = (dst->h * (src_max_y - src->y)) / (src->h); src->h = src_max_y - src->y; } if (dst->h <= 0) return 0; if (src->h <= 0) return 0; if (dst_clip->y < 0) { dst_clip->h += dst_clip->y; dst_clip->y = 0; } if (dst_clip->h <= 0) return 0; if (dst_clip->y >= dst_max_y) return 0; _shrink(&dst_clip->y, &dst_clip->h, 0, dst_max_y); if (dst_clip->h <= 0) return 0; return 1; } static void _soft8_image_draw_sampled_int(Soft8_Image * src, Soft8_Image * dst, RGBA_Draw_Context * dc, Eina_Rectangle sr, Eina_Rectangle dr) { Eina_Rectangle cr; if (! (RECTS_INTERSECT (dr.x, dr.y, dr.w, dr.h, 0, 0, dst->cache_entry.w, dst->cache_entry.h))) return; if (! (RECTS_INTERSECT (sr.x, sr.y, sr.w, sr.h, 0, 0, src->cache_entry.w, src->cache_entry.h))) return; _get_clip(dc, dst, &cr); if (!_soft8_adjust_areas (&sr, src->cache_entry.w, src->cache_entry.h, &dr, dst->cache_entry.w, dst->cache_entry.h, &cr)) return; if ((dr.w == sr.w) && (dr.h == sr.h)) evas_common_soft8_image_draw_unscaled(src, dst, dc, sr, dr, cr); else evas_common_soft8_image_draw_scaled_sampled(src, dst, dc, sr, dr, cr); } EAPI void evas_common_soft8_image_draw(Soft8_Image * src, Soft8_Image * dst, RGBA_Draw_Context * dc, int src_region_x, int src_region_y, int src_region_w, int src_region_h, int dst_region_x, int dst_region_y, int dst_region_w, int dst_region_h, int smooth __UNUSED__) { static Cutout_Rects *rects = NULL; Eina_Rectangle sr, dr; Cutout_Rect *r; struct RGBA_Draw_Context_clip clip_bkp; int i; /* handle cutouts here! */ EINA_RECTANGLE_SET(&dr, dst_region_x, dst_region_y, dst_region_w, dst_region_h); if (_is_empty_rectangle(&dr)) return; if (! (RECTS_INTERSECT (dr.x, dr.y, dr.w, dr.h, 0, 0, dst->cache_entry.w, dst->cache_entry.h))) return; EINA_RECTANGLE_SET(&sr, src_region_x, src_region_y, src_region_w, src_region_h); if (_is_empty_rectangle(&sr)) return; if (! (RECTS_INTERSECT (sr.x, sr.y, sr.w, sr.h, 0, 0, src->cache_entry.w, src->cache_entry.h))) return; /* no cutouts - cut right to the chase */ if (!dc->cutout.rects) { _soft8_image_draw_sampled_int(src, dst, dc, sr, dr); return; } /* save out clip info */ clip_bkp = dc->clip; evas_common_draw_context_clip_clip(dc, 0, 0, dst->cache_entry.w, dst->cache_entry.h); evas_common_draw_context_clip_clip(dc, dst_region_x, dst_region_y, dst_region_w, dst_region_h); /* our clip is 0 size.. abort */ if ((dc->clip.w <= 0) || (dc->clip.h <= 0)) { dc->clip = clip_bkp; return; } rects = evas_common_draw_context_apply_cutouts(dc, rects); for (i = 0; i < rects->active; i++) { r = rects->rects + i; evas_common_draw_context_set_clip(dc, r->x, r->y, r->w, r->h); _soft8_image_draw_sampled_int(src, dst, dc, sr, dr); } dc->clip = clip_bkp; } EAPI Soft8_Image * evas_common_soft8_image_alpha_set(Soft8_Image * im, int have_alpha) { Soft8_Image *new_im; if (im->cache_entry.flags.alpha == have_alpha) return im; new_im = (Soft8_Image *) evas_cache_image_alone(&im->cache_entry); new_im->cache_entry.flags.alpha = have_alpha; if (im->cache_entry.w > 0 && im->cache_entry.h) new_im = (Soft8_Image *) evas_cache_image_size_set(&new_im->cache_entry, im->cache_entry.w, im->cache_entry.h); return new_im; } /* Soft16_Image * */ /* evas_common_soft16_image_size_set(Soft16_Image *old_im, unsigned int w, unsigned int h) */ /* { */ /* Soft16_Image *new_im; */ /* DATA16 *dp, *sp; */ /* int i, cw, ch, ew; */ /* if ((old_im->cache_entry.w == w) && (old_im->cache_entry.h == h)) return old_im; */ /* new_im = evas_common_soft16_image_new(w, h, -1, old_im->flags.have_alpha, NULL, 1); */ /* if (old_im->cache_entry.w < new_im->cache_entry.w) */ /* cw = old_im->cache_entry.w; */ /* else */ /* cw = new_im->cache_entry.w; */ /* ew = new_im->cache_entry.w - cw; */ /* if (old_im->cache_entry.h < new_im->cache_entry.h) */ /* ch = old_im->cache_entry.h; */ /* else */ /* ch = new_im->cache_entry.h; */ /* dp = new_im->pixels; */ /* sp = old_im->pixels; */ /* for (i = 0; i < ch; i++) */ /* { */ /* memcpy(dp, sp, cw * sizeof(DATA16)); */ /* if (ew > 0) memset(dp, 0, ew * sizeof(DATA16)); */ /* dp += new_im->stride; */ /* sp += old_im->stride; */ /* } */ /* if (old_im->flags.have_alpha) */ /* { */ /* DATA8 *dp, *sp; */ /* dp = new_im->alpha; */ /* sp = old_im->alpha; */ /* for (i = 0; i < ch; i++) */ /* { */ /* memcpy(dp, sp, cw * sizeof(DATA8)); */ /* if (ew > 0) memset(dp, 0, ew * sizeof(DATA8)); */ /* dp += new_im->stride; */ /* sp += old_im->stride; */ /* } */ /* } */ /* evas_cache_image_drop(&old_im->cache_entry); */ /* return new_im; */ /* } */