From 653a94a4a40c2f1c01bdda9345c999f91c310b27 Mon Sep 17 00:00:00 2001 From: lecoanet Date: Thu, 4 Mar 2004 08:39:15 +0000 Subject: * Adaptation for perl/Tk 804. * Changed the image texture handling code now that only one context is kept for each display. * A reference count is kept for images with multiple clients with same proc/procdata. This will prevent early deallocation in this case. * Fixed a bug in the image update procedure when re-creating an existing image. The transient deleted state was not properly handled and the type of image can change in the process as well as the pointer to the photo structure. * Font texture is cached once per display instead of once per widget. --- generic/Image.c | 111 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 38 deletions(-) (limited to 'generic/Image.c') diff --git a/generic/Image.c b/generic/Image.c index 7802b31..09ecdd3 100644 --- a/generic/Image.c +++ b/generic/Image.c @@ -38,6 +38,7 @@ #include #endif +#include static const char rcsid[] = "$Id$"; static const char compile_id[] = "$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; @@ -52,6 +53,7 @@ static Tcl_HashTable font_textures; typedef struct _ClientStruct { void (*inv_proc)(void *cd); void *client_data; + int refcount; } ClientStruct; typedef struct _ImageStruct { @@ -132,14 +134,17 @@ InvalidateImage(ClientData client_data, int y __unused, int width __unused, int height __unused, - int image_width __unused, - int image_height __unused) + int image_width, + int image_height) { ImageBits *bits = (ImageBits *) client_data; Image this; int num_cs, count, i; ClientStruct *cs; + char *image_name; + /* printf("Invalidation, bits: %d, %d %d %d %d %d %d\n", + client_data, x, y, width, height, image_width, image_height);*/ if (ZnImageIsBitmap(bits->images)) { /* This is a bitmap nothing to update * (This should not happen) */ @@ -157,15 +162,20 @@ InvalidateImage(ClientData client_data, bits->valid_region = NULL; } + bits->width = image_width; + bits->height = image_height; + image_name = ZnNameOfImage(bits->images); + + /* + * The photo pointer must be updated. It changes when creating an new image with + * the same name as an old. The image is first deleted then re-instantiated. + * As a side effect we also rely on it for telling if an image is a photo. + */ + bits->tkphoto = Tk_FindPhoto(bits->wi->interp, image_name); + count = 0; this = bits->images; while (this) { - if (bits->tkphoto) { - Tk_PhotoGetSize(bits->tkphoto, &bits->width, &bits->height); - } - else { - Tk_SizeOfImage(bits->tkimage, &bits->width, &bits->height); - } #ifdef GL if (this->for_gl) { if (this->i.texobj) { @@ -197,7 +207,6 @@ InvalidateImage(ClientData client_data, } /*printf("Invalidate on image %s with %d clients\n", Tcl_GetHashKey(&images, bits->hash), count);*/ - } ZnImage @@ -222,11 +231,11 @@ ZnGetImage(ZnWInfo *wi, image_name = Tk_GetUid(image_name); entry = Tcl_FindHashEntry(&images, image_name); if (entry != NULL) { - /*printf("Image %s déjà connue\n", image_name);*/ + /*printf("Image \"%s\" is in cache\n", image_name);*/ bits = (ImageBits *) Tcl_GetHashValue(entry); } else { - /*printf("Nouvelle Image %s\n", image_name);*/ + /*printf("New image \"%s\"\n", image_name);*/ if (strcmp(image_name, "") == 0) { return ZnUnspecifiedImage; } @@ -314,7 +323,7 @@ ZnGetImage(ZnWInfo *wi, */ for (image = bits->images; image != NULL; image = image->next) { if (image->for_gl == for_gl) { - if ((for_gl && (image->wi == wi)) || + if ((for_gl && (image->wi->dpy == wi->dpy)) || (!for_gl && (image->wi->screen == wi->screen))) { if (!ZnImageIsBitmap(image)) { cs_ptr = ZnListArray(image->clients); @@ -322,6 +331,7 @@ ZnGetImage(ZnWInfo *wi, for (i = 0; i < num_cs; i++, cs_ptr++) { if ((cs_ptr->inv_proc == inv_proc) && (cs_ptr->client_data == client_data)) { + cs_ptr->refcount++; return image; } } @@ -329,7 +339,9 @@ ZnGetImage(ZnWInfo *wi, */ cs.inv_proc = inv_proc; cs.client_data = client_data; + cs.refcount = 1; ZnListAdd(image->clients, &cs, ZnListTail); + return image; } image->refcount++; return image; @@ -340,9 +352,10 @@ ZnGetImage(ZnWInfo *wi, /* * Create a new instance for this case. */ + /*printf("new instance for \"%s\"\n", image_name);*/ image = ZnMalloc(sizeof(ImageStruct)); image->bits = bits; - image->refcount = 1; + image->refcount = 0; image->for_gl = for_gl; image->wi = wi; @@ -350,8 +363,12 @@ ZnGetImage(ZnWInfo *wi, image->clients = ZnListNew(1, sizeof(ClientStruct)); cs.inv_proc = inv_proc; cs.client_data = client_data; + cs.refcount = 1; ZnListAdd(image->clients, &cs, ZnListTail); } + else { + image->refcount++; + } /* Init the real resource and let the client load it * on demand */ @@ -395,15 +412,19 @@ ZnGetImageByValue(ZnImage image, for (i = 0; i < num_cs; i++, cs_ptr++) { if ((cs_ptr->inv_proc == inv_proc) && (cs_ptr->client_data == client_data)) { + cs_ptr->refcount++; return image; } } cs.inv_proc = inv_proc; cs.client_data = client_data; + cs.refcount = 1; ZnListAdd(this->clients, &cs, ZnListTail); } + else { + this->refcount++; + } - this->refcount++; return image; } @@ -435,7 +456,7 @@ ZnFreeImage(ZnImage image, Image prev, scan, this = ((Image) image); ImageBits *bits = this->bits; ClientStruct *cs_ptr; - int i, num_cs; + int i, num_cs, rm_image; /*printf("ZnFreeImage: %s\n", ZnNameOfImage(image));*/ /* @@ -453,16 +474,21 @@ ZnFreeImage(ZnImage image, for (i = 0; i < num_cs; i++, cs_ptr++) { if ((cs_ptr->inv_proc == inv_proc) && (cs_ptr->client_data == client_data)) { - ZnListDelete(this->clients, i); - this->refcount--; + cs_ptr->refcount--; + if (cs_ptr->refcount == 0) { + ZnListDelete(this->clients, i); + } break; } } + rm_image = ZnListSize(this->clients)==0; } else { this->refcount--; + rm_image = this->refcount==0; } - if (this->refcount != 0) { + + if (!rm_image) { return; } @@ -478,9 +504,12 @@ ZnFreeImage(ZnImage image, if (this->for_gl) { #ifdef GL ZnWInfo *wi = this->wi; - if (this->i.texobj && wi->win) { + if (this->i.texobj) { ZnGLMakeCurrent(wi); + /* printf("%d Libération de la texture %d pour l'image %s\n", + wi, this->i.texobj, ZnNameOfImage(image));*/ glDeleteTextures(1, &this->i.texobj); + this->i.texobj = 0; ZnGLRelease(wi); } #endif @@ -954,6 +983,7 @@ ZnImageTex(ZnImage image, t_stride = bits->t_width * 4; t_size = t_stride * bits->t_height; + /*printf("t_width: %d(%d), t_height: %d(%d)\n", bits->t_width, width, bits->t_height, height);*/ bits->t_bits = ZnMalloc(t_size); Tk_PhotoGetImage(bits->tkphoto, &block); green_off = block.offset[1] - block.offset[0]; @@ -1006,8 +1036,8 @@ ZnImageTex(ZnImage image, if (!this->i.texobj) { glGenTextures(1, &this->i.texobj); - /*printf("creation texture %d pour image %s\n", - this->i.texobj, ZnNameOfImage(this));*/ + /*printf("%d creation texture %d pour image %s\n", + bits, this->i.texobj, ZnNameOfImage(this));*/ glBindTexture(GL_TEXTURE_2D, this->i.texobj); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); @@ -1027,7 +1057,7 @@ ZnImageTex(ZnImage image, if (glGetError() != GL_NO_ERROR) { ZnWarning("Can't allocate the texture for image "); ZnWarning(ZnNameOfImage(image)); - ZnWarning("\n"); + ZnWarning("\n"); } glBindTexture(GL_TEXTURE_2D, 0); } @@ -1063,8 +1093,8 @@ typedef struct { } TexGlyphInfo; typedef struct _TexFontInfo { - GLuint texobj; struct _TexFont *txf; + GLuint texobj; ZnWInfo *wi; unsigned int refcount; struct _TexFontInfo *next; @@ -1084,7 +1114,7 @@ typedef struct _TexFont { TexGlyphInfo *tgi; ZnTexGVI *tgvi; ZnTexGVI **lut; -#ifndef PTK +#ifndef PTK_800 Tcl_Encoding enc; #endif Tcl_HashEntry *hash; @@ -1193,7 +1223,7 @@ placeGlyph(FontInfoPtr font, } } -#ifdef PTK +#ifdef PTK_800 FontInfoPtr SuckGlyphsFromServer(ZnWInfo *wi, Tk_Font font) @@ -1211,7 +1241,7 @@ SuckGlyphsFromServer(ZnWInfo *wi, unsigned int width, height, length, pixwidth; unsigned int i, j; char str_from[] = " "; -#ifndef PTK +#ifndef PTK_800 char str_utf[8]; #endif unsigned char *bitmapData = NULL; @@ -1246,7 +1276,7 @@ SuckGlyphsFromServer(ZnWInfo *wi, width = 0; for (i = 0; i < myfontinfo->num_glyphs; i++) { *str_from = i + myfontinfo->min_char; -#ifdef PTK +#ifdef PTK_800 Tk_MeasureChars(font, str_from, 1, 0, TK_AT_LEAST_ONE, &length); #else Tcl_ExternalToUtf(wi->interp, enc, str_from, 1, @@ -1289,7 +1319,7 @@ SuckGlyphsFromServer(ZnWInfo *wi, numToGrab = 0; for (i = 0; i < myfontinfo->num_glyphs; i++) { *str_from = i + myfontinfo->min_char; -#ifdef PTK +#ifdef PTK_800 Tk_MeasureChars(font, str_from, 1, 0, TK_AT_LEAST_ONE, &charWidth); #else Tcl_ExternalToUtf(wi->interp, enc, str_from, 1, @@ -1305,7 +1335,7 @@ SuckGlyphsFromServer(ZnWInfo *wi, myfontinfo->glyph[i].advance = charWidth; myfontinfo->glyph[i].bitmap = NULL; if (charWidth != 0) { -#ifdef PTK +#ifdef PTK_800 Tk_DrawChars(wi->dpy, offscreen, xgc, font, str_from, 1, (int) (8*maxSpanLength*numToGrab), myfontinfo->ascent); #else @@ -1376,7 +1406,7 @@ SuckGlyphsFromServer(ZnWInfo *wi, return NULL; } -#ifndef PTK +#ifndef PTK_800 Tcl_Encoding ZnGetFontEncoding(ZnWInfo *wi, Tk_Font tkfont) @@ -1457,12 +1487,17 @@ ZnGetTexFont(ZnWInfo *wi, int width, height; unsigned int texw, texh; GLfloat xstep, ystep; + TkFont *tft = (TkFont *) font; if (!inited) { Tcl_InitHashTable(&font_textures, TCL_ONE_WORD_KEYS); inited = 1; } + /* printf("family: %s, size: %d, weight: %d, slant: %d, underline: %d, overstrike: %d\n", + tft->fa.family, tft->fa.size, tft->fa.weight, tft->fa.slant, tft->fa.underline, + tft->fa.overstrike); + */ entry = Tcl_FindHashEntry(&font_textures, (char *) font); if (entry != NULL) { txf = (TexFont *) Tcl_GetHashValue(entry); @@ -1480,13 +1515,13 @@ ZnGetTexFont(ZnWInfo *wi, /* Get a local reference to the font, it will be deallocated * when no further references on this TexFont exist. */ txf->tkfont = Tk_GetFont(wi->interp, wi->win, Tk_NameOfFont(font)); -#ifndef PTK +#ifndef PTK_800 txf->enc = ZnGetFontEncoding(wi, txf->tkfont); #endif /*printf("Chargement de la texture pour la fonte %s\n", ZnNameOfTexFont(tfi));*/ -#ifdef PTK +#ifdef PTK_800 fontinfo = SuckGlyphsFromServer(wi, txf->tkfont); #else fontinfo = SuckGlyphsFromServer(wi, txf->tkfont, txf->enc); @@ -1714,7 +1749,7 @@ ZnGetTexFont(ZnWInfo *wi, ZnFree(txf->teximage); txf->teximage = NULL; } -#ifndef PTK +#ifndef PTK_800 Tcl_FreeEncoding(txf->enc); #endif Tk_FreeFont(txf->tkfont); @@ -1747,7 +1782,7 @@ ZnGetTexFont(ZnWInfo *wi, * Now locate the texture obj in the texture list for this widget. */ for (tfi = txf->tfi; tfi != NULL; tfi = tfi->next) { - if (tfi->wi == wi) { + if (tfi->wi->dpy == wi->dpy) { tfi->refcount++; return tfi; } @@ -1760,9 +1795,9 @@ ZnGetTexFont(ZnWInfo *wi, return NULL; } tfi->refcount = 1; - tfi->texobj = 0; tfi->wi = wi; tfi->txf = txf; + tfi->texobj = 0; tfi->next = txf->tfi; txf->tfi = tfi; @@ -1861,7 +1896,7 @@ ZnFreeTexFont(ZnTexFontInfo tfi) else { prev->next = this->next; } - if (this->texobj && wi->win) { + if (this->texobj) { /*printf("%d Libération de la texture %d pour la fonte %s\n", wi, this->texobj, ZnNameOfTexFont(tfi));*/ ZnGLMakeCurrent(wi); @@ -1880,7 +1915,7 @@ ZnFreeTexFont(ZnTexFontInfo tfi) ZnFree(txf->tgvi); ZnFree(txf->lut); ZnFree(txf->teximage); -#ifndef PTK +#ifndef PTK_800 Tcl_FreeEncoding(txf->enc); #endif Tcl_DeleteHashEntry(txf->hash); @@ -1918,7 +1953,7 @@ ZnCharInTexFont(ZnTexFontInfo tfi, * ********************************************************************************** */ -#ifndef PTK +#ifndef PTK_800 Tcl_Encoding ZnTexFontEncoding(ZnTexFontInfo tfi) { -- cgit v1.1