diff options
author | mdankov <mdankov@ffa7fe5e-494d-0410-b361-a75ebd5db220> | 2012-05-20 10:03:43 +0000 |
---|---|---|
committer | mdankov <mdankov@ffa7fe5e-494d-0410-b361-a75ebd5db220> | 2012-05-20 10:03:43 +0000 |
commit | 161c8c131d26ad36e5a26aa64dedf614089cc6f8 (patch) | |
tree | 9ade9c00a6c3a1def3f82770a5dce29930b59e64 /navit/graphics.c | |
parent | 42147646bbe3b02befdc7dcc3ef9611dc43d4e29 (diff) | |
download | navit-svn-161c8c131d26ad36e5a26aa64dedf614089cc6f8.tar.gz |
Fix:core:Move icon name guessing code from gui_internal to graphics.c. Implement image caching in graphics.c. Fixes #1036.
git-svn-id: http://svn.code.sf.net/p/navit/code/trunk/navit@5107 ffa7fe5e-494d-0410-b361-a75ebd5db220
Diffstat (limited to 'navit/graphics.c')
-rw-r--r-- | navit/graphics.c | 156 |
1 files changed, 140 insertions, 16 deletions
diff --git a/navit/graphics.c b/navit/graphics.c index 9424cca6..62d8af95 100644 --- a/navit/graphics.c +++ b/navit/graphics.c @@ -78,6 +78,7 @@ struct graphics * Counter for z_order of displayitems; */ int current_z_order; + GHashTable *image_cache_hash; }; struct display_context @@ -244,6 +245,7 @@ struct graphics * graphics_new(struct attr *parent, struct attr **attrs) this_->contrast=65536; this_->gamma=65536; this_->font_size=20; + this_->image_cache_hash = g_hash_table_new(g_str_hash, g_str_equal); while (*attrs) { graphics_set_attr_do(this_,*attrs); attrs++; @@ -276,6 +278,7 @@ struct graphics * graphics_overlay_new(struct graphics *parent, struct point *p, return NULL; this_=g_new0(struct graphics, 1); this_->priv=parent->meth.overlay_new(parent->priv, &this_->meth, p, w, h, alpha, wraparound); + this_->image_cache_hash = parent->image_cache_hash; this_->parent = parent; pr.lu.x=0; pr.lu.y=0; @@ -402,6 +405,22 @@ void graphics_free(struct graphics *gra) { if (!gra) return; + + /* If it's not an overlay, free the image cache. */ + if(!gra->parent) { + GHashTableIter iter; + char *key; + struct graphics_image *img; + g_hash_table_iter_init (&iter, gra->image_cache_hash); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &img)) { + g_hash_table_iter_remove (&iter); + g_free(key); + if (img && gra->meth.image_free) + gra->meth.image_free(gra->priv, img->priv); + g_free(img); + } + } + graphics_gc_destroy(gra->gc[0]); graphics_gc_destroy(gra->gc[1]); graphics_gc_destroy(gra->gc[2]); @@ -570,17 +589,7 @@ void graphics_gc_set_dashes(struct graphics_gc *gc, int width, int offset, unsig */ struct graphics_image * graphics_image_new_scaled(struct graphics *gra, char *path, int w, int h) { - struct graphics_image *this_; - - this_=g_new0(struct graphics_image,1); - this_->height=h; - this_->width=w; - this_->priv=gra->meth.image_new(gra->priv, &this_->meth, path, &this_->width, &this_->height, &this_->hot, 0); - if (! this_->priv) { - g_free(this_); - this_=NULL; - } - return this_; + return graphics_image_new_scaled_rotated(gra, path, w, h, 0); } /** @@ -596,15 +605,132 @@ struct graphics_image * graphics_image_new_scaled(struct graphics *gra, char *pa struct graphics_image * graphics_image_new_scaled_rotated(struct graphics *gra, char *path, int w, int h, int rotate) { struct graphics_image *this_; + char* hash_key = g_strdup_printf("%s*%d*%d*%d",path,w,h,rotate); + + if ( g_hash_table_lookup_extended( gra->image_cache_hash, hash_key, NULL, (gpointer)&this_) ) { + g_free(hash_key); + dbg(3,"Found cached image%sfor '%s'\n",this_?" ":" miss ",path); + return this_; + } this_=g_new0(struct graphics_image,1); this_->height=h; this_->width=w; - this_->priv=gra->meth.image_new(gra->priv, &this_->meth, path, &this_->width, &this_->height, &this_->hot, rotate); + + if(!this_->priv) { + char *ext; + char *s, *name, *new_name; + int len=strlen(path); + int i,k; + int newwidth=-1, newheight=-1; + + ext=g_utf8_strrchr(path,-1,'.'); + i=path-ext+len; + + /* Dont allow too long or too short file name extensions*/ + if(ext && ((i>5) || (i<1))) + ext=NULL; + + /* Search for _w_h name part, begin from char before extension if it exists */ + if(ext) + s=ext-1; + else + s=path+len; + + k=1; + while(s>path && g_ascii_isdigit(*s)) { + if(newheight<0) + newheight=0; + newheight+=(*s-'0')*k; + k*=10; + s--; + } + + if(k>1 && s>path && *s=='_') { + k=1; + s--; + while(s>path && g_ascii_isdigit(*s)) { + if(newwidth<0) + newwidth=0; + newwidth+=(*s-'0')*k;; + k*=10; + s--; + } + } + + if(k==1 || s<=path || *s!='_') { + newwidth=-1; + newheight=-1; + if(ext) + s=ext; + else + s=path+len; + + } + + /* If exact h and w values were given as function parameters, they take precedence over values guessed from the image name */ + if(w!=-1) + newwidth=w; + if(h!=-1) + newheight=h; + + name=g_strndup(path,s-path); + for (i = 1 ; i < 6 ; i++) { + new_name=NULL; + switch (i) { + case 1: + /* The best variant both for cpu usage and quality would be prescaled png of a needed size */ + if (newwidth != -1 && newheight != -1) { + new_name=g_strdup_printf("%s_%d_%d.png", name, newwidth, newheight); + } + break; + case 2: + /* Try to load image by the exact name given by user. For example, if she wants to + scale some prescaled png variant to a new size given as function params, or have + default png image to be displayed unscaled. */ + new_name=g_strdup(path); + break; + case 3: + /* Next, try uncompressed and compressed svgs as they should give best quality but + rendering might take more cpu resources when the image is displayed for the first time */ + new_name=g_strdup_printf("%s.svg", name); + break; + case 4: + new_name=g_strdup_printf("%s.svgz", name); + break; + case 5: + /* Scaling the default png to the needed size may give some quality loss */ + new_name=g_strdup_printf("%s.png", name); + break; + case 6: + /* xpm format is used as a last resort, because its not widely supported and we are moving to svg and png formats */ + new_name=g_strdup_printf("%s.xpm", name); + break; + } + if (! new_name) + continue; + + this_->width=newwidth; + this_->height=newheight; + dbg(2,"Trying to load image '%s' for '%s' at %dx%d\n", new_name, path, newwidth, newheight); + this_->priv=gra->meth.image_new(gra->priv, &this_->meth, new_name, &this_->width, &this_->height, &this_->hot, rotate); + if (this_->priv) { + dbg(1,"Using image '%s' for '%s' at %dx%d\n", new_name, path, newwidth, newheight); + break; + } + g_free(new_name); + } + g_free(name); + } + if (! this_->priv) { + dbg(0,"No image for '%s'\n", path); g_free(this_); this_=NULL; } + + g_hash_table_insert(gra->image_cache_hash, hash_key, (gpointer)this_ ); + return this_; } @@ -617,7 +743,7 @@ struct graphics_image * graphics_image_new_scaled_rotated(struct graphics *gra, */ struct graphics_image * graphics_image_new(struct graphics *gra, char *path) { - return graphics_image_new_scaled(gra, path, -1, -1); + return graphics_image_new_scaled_rotated(gra, path, -1, -1, 0); } /** @@ -628,9 +754,7 @@ struct graphics_image * graphics_image_new(struct graphics *gra, char *path) */ void graphics_image_free(struct graphics *gra, struct graphics_image *img) { - if (gra->meth.image_free) - gra->meth.image_free(gra->priv, img->priv); - g_free(img); + /* Image is cached inside gra->image_cache_hash. So it would be freed only when graphics is destroyed => Do nothing here. */ } /** |