Logo Search packages:      
Sourcecode: tcltk8.0-ja version File versions  Download package

tkUnixFontCache.c

/* 
 * tkUnixFontCache.c
 *
 *      This file contains modules to improve performance of font handling.
 *
 *    Author:     m-hirano@sra.co.jp
 *
 * Copyright 1998 Software Research Associates, Inc.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Software Research Associates not be
 * used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.  Software Research
 * Associates makes no representations about the suitability of this software
 * for any purpose.  It is provided "as is" without express or implied
 * warranty.
 */

#ifndef lint
static char rcsid[] = "$Id: tkUnixFontCache.c,v 1.15 1998/12/04 20:01:26 m-hirano Exp $";
#endif /* !lint */

#ifdef KANJI

#define CACHE_INCORE

#include "tclInt.h"
#include "tkPort.h"
#include "tkInt.h"

#include "tkFont.h"

#ifndef Xmalloc
#ifdef MALLOC_0_RETURNS_NULL

# define Xmalloc(size) malloc(((size) == 0 ? 1 : (size)))
# define Xrealloc(ptr, size) realloc((ptr), ((size) == 0 ? 1 : (size)))
# define Xcalloc(nelem, elsize) calloc(((nelem) == 0 ? 1 : (nelem)), (elsize))

#else

# define Xmalloc(size) malloc((size))
# define Xrealloc(ptr, size) realloc((ptr), (size))
# define Xcalloc(nelem, elsize) calloc((nelem), (elsize))

#endif
#endif /* Xmalloc */

typedef struct {
    Tk_Uid name;
    XFontSet xFontSet;
    int refCount;
    Tcl_HashEntry *entry;
} TkpFontSetCache;

typedef struct {
    Tk_Uid name;
    Display *dpy;
} TkpFontSetCacheKey;

typedef struct TkpFontNameAlias {
    Tcl_HashEntry *entry;
    struct TkpFontNameAlias *next;
} TkpFontNameAliasRec;
    
typedef struct {
    Tk_Uid name;
    Display *dpy;
    XFontStruct *xFontPtr;
    int refCount;
    int maxRef;
    TkpFontNameAliasRec *alias;
    TkpFontNameAliasRec *aTail;
    int toBeFree;
} TkpFontCache;

typedef struct {
    Tk_Uid name;
    Display *dpy;
} TkpFontCacheKey;

typedef struct {
    char **nameList;
    int numFonts;
    Tcl_HashTable exactTable;
} TkpFontList;


static Tcl_HashTable xFontSetKeyTable;
static Tcl_HashTable xFontSetCacheTable;

static Tcl_HashTable xFontKeyTable;
static Tcl_HashTable xFontCacheTable;

static Tcl_HashTable xFontListTable;

Tcl_HashTable xFindFontTable;
Tcl_HashTable needXFreeFontListTable;

void
TkpFontCachePkgInit()
{
    static int xFontCacheInited = 0;

    if (xFontCacheInited == 0) {
      Tcl_InitHashTable(&xFindFontTable, TCL_STRING_KEYS);
      Tcl_InitHashTable(&needXFreeFontListTable, TCL_ONE_WORD_KEYS);
      Tcl_InitHashTable(&xFontListTable, TCL_ONE_WORD_KEYS);
      Tcl_InitHashTable(&xFontCacheTable, sizeof(TkpFontCacheKey)/sizeof(int));
      Tcl_InitHashTable(&xFontKeyTable, TCL_ONE_WORD_KEYS);
        Tcl_InitHashTable(&xFontSetCacheTable, sizeof(TkpFontSetCacheKey)/sizeof(int));
        Tcl_InitHashTable(&xFontSetKeyTable, TCL_ONE_WORD_KEYS);
      xFontCacheInited = 1;
    }
}

static char regBuf[4096];
static char *
PatternToRegexp(pat)
    char *pat;
{
    char *ret = regBuf;
    char *start = pat;
    int lastIsDoller = 0;

    if (*start != '*') {
      *ret = '^';
      ret++;
    }
    if (start[strlen(start) - 1] != '*') {
      lastIsDoller = 1;
    }
    while (*start != 0) {
      switch (*start) {
          case '*': {
            *ret = '.';
            ret++;
            *ret = '*';
            break;
          }
          case '-': {
            *ret = '-';
            break;
          }
          default: {
            if (isalpha(*start)) {
                *ret = tolower(*start);
            } else {
                *ret = *start;
            }
            break;
          }
      }
      start++;
      ret++;
    }
    if (lastIsDoller == 1) {
      *ret = '$';
      ret++;
    }
    *ret = 0;
    return regBuf;
}


static int
fontComp(a, b)
    char **a, **b;
{
    char *s0 = *a;
    char *s1 = *b;
    while (*s0 && *s1 && *s0 == *s1) {
      s0++;
      s1++;
    }
    return (*s0 - *s1);
}


static TkpFontList *
GetFontListByDisplay(dpy)
    Display *dpy;
{
    TkpFontList *ret = NULL;
    int num;
#ifdef USE_OWN_XLSFONT
    char **list = TkUnixXListFonts(dpy, "*", 100000, &num);
#else
    char **list = XListFonts(dpy, "*", 100000, &num);
#endif /* USE_OWN_XLSFONT */
    if (list != NULL && num > 0) {
      char *tmp;
      int i;
      for (i = 0; i < num; i++) {
          tmp = list[i];
          while (*tmp != 0) {
            if (isalpha(*tmp)) {
                *tmp = tolower(*tmp);
            }
            tmp++;
          }
      }
      qsort(&(list[0]), (unsigned int)num, sizeof(char *), fontComp);
      ret = (TkpFontList *)ckalloc(sizeof(TkpFontList));
      ret->nameList = list;
      ret->numFonts = num;
      Tcl_InitHashTable(&(ret->exactTable), TCL_STRING_KEYS);
    }
    return ret;
}


char **
#ifdef USE_OWN_XLSFONT
#if NeedFunctionPrototypes
XListFonts(
    Display *dpy,
    _Xconst char *pat,
    int maxNum,
    int *numNames
)
#else
XListFonts(dpy, pat, maxNum, numNames)
    Display *dpy;
    _Xconst char *pat;
    int maxNum;
    int *numNames;
#endif /* NeedFunctionPrototypes */
#else
TkpListFonts(dpy, pat, maxNum, numNames)
    Display *dpy;
    char *pat;
    int maxNum;
    int *numNames;
#endif /* USE_OWN_XLSFONT */
{
    TkpFontList *newFontList = NULL;
    int new;
    Tcl_HashEntry *entry = NULL;
    Tcl_HashTable *eTable = NULL;
    char **fontList = NULL;
    int fontNum = 0;
    regexp *compPat = NULL;
    char **ret = NULL;
    int matches = 0;
    int i;
    char **found = NULL;

    if (numNames != NULL) *numNames = 0;

    entry = Tcl_CreateHashEntry(&xFontListTable, (char *)dpy, &new);
    if (new == 0) {
      newFontList = (TkpFontList *)Tcl_GetHashValue(entry);
    } else {
      newFontList = GetFontListByDisplay(dpy);
      if (newFontList == NULL) {
          Tcl_DeleteHashEntry(entry);
          panic("can't get all font list in X server.");
      }
      Tcl_SetHashValue(entry, (ClientData)newFontList);
    }
    fontList = newFontList->nameList;
    fontNum = newFontList->numFonts;
    eTable = &(newFontList->exactTable);

    if (strchr(pat, '*') == NULL) {
      char buf[4096];
      char *bCp = buf;
      char *pCp = (char *)pat;
      int new;

      entry = Tcl_CreateHashEntry(eTable, (char *)pat, &new);
      if (new == 0) {
          ret = (char **)ckalloc(sizeof(char *));
          ret[0] = (char *)Tcl_GetHashValue(entry);
          if (numNames != NULL) *numNames = 1;
          return ret;
      }

      while (*pCp != 0) {
          if (isalpha(*pCp)) {
            *bCp = tolower(*pCp);
          } else {
            *bCp = *pCp;
          }
          pCp++;
          bCp++;
      }
      *bCp = 0;
      bCp = buf;
      found = (char **)bsearch(&bCp, &(fontList[0]), (unsigned int)fontNum,
                         sizeof(char *), fontComp);
      if (found != NULL) {
          ret = (char **)ckalloc(sizeof(char *));
          ret[0] = (char *)pat;
          if (numNames != NULL) *numNames = 1;
          Tcl_SetHashValue(entry, (ClientData)Tk_GetUid(pat));
          return ret;
      } else {
          /* 
           * Maybe it is not in '*' list, but X server could say "I
           * have this one."
           */
          int numList;
#ifdef USE_OWN_XLSFONT
          char **nameList = TkUnixXListFonts(dpy, (char *)pat, 1, &numList);
#else
          char **nameList = XListFonts(dpy, pat, 1, &numList);
#endif /* USE_OWN_XLSFONT */
          if (nameList != NULL && numList > 0) {
            ret = (char **)ckalloc(sizeof(char *));         
            ret[0] = (char *)pat;
            if (numNames != NULL) *numNames = 1;            
            Tcl_SetHashValue(entry, (ClientData)Tk_GetUid(pat));
#ifdef USE_OWN_XLSFONT
            TkUnixXFreeFontNames(nameList);
#else
            XFreeFontNames(nameList);
#endif /* USE_OWN_XLSFONT */
            return ret;
          }
      }
          
      Tcl_DeleteHashEntry(entry);
    }

    compPat = TclRegComp(PatternToRegexp(pat));
    if (compPat == NULL) {
      panic("regcomp NULL");
      return NULL;
    }
    ret = (char **)ckalloc(sizeof(char **) * fontNum);
    
    for (i = 0; i < fontNum; i++) {
      if (TclRegExec(compPat, fontList[i], fontList[i]) != 0) {
          ret[matches] = fontList[i];
          matches++;
      }
    }
    ckfree(compPat);

    if (matches > 0) {
      if (numNames != NULL) *numNames = (matches > maxNum) ? maxNum : matches;
    } else {
      /*
       * Mayhaps resizeable font list. Ask server.
       */
      int xNumList;
#ifdef USE_OWN_XLSFONT
      char **xNameList = TkUnixXListFonts(dpy, (char *)pat, maxNum, &xNumList);
#else 
      char **xNameList = XListFonts(dpy, pat, maxNum, &xNumList);
#endif /* USE_OWN_XLSFONT */
      ckfree(ret);
      ret = NULL;
      if (numNames != NULL) *numNames = xNumList;
      if (xNameList != NULL && xNumList > 0) {
          new = 0;
          entry = Tcl_CreateHashEntry(&needXFreeFontListTable, (char *)xNameList, &new);
          if (new == 0) {
            panic("Maybe non-freed memory alloc'd by XListFonts().");
          }
          Tcl_SetHashValue(entry, (ClientData)xNameList);
          ret = xNameList;
      }
    }
    return ret;
}
    
int
#ifdef USE_OWN_XLSFONT
#if NeedFunctionPrototypes
XFreeFontNames(
    char **list
)
#else
XFreeFontNames(list)
    char **list;
#endif /* NeedFunctionPrototypes */
#else
TkpFreeFontNames(list)
    char **list;
#endif /* USE_OWN_XLSFONT */
{
    Tcl_HashEntry *entry;

    entry = Tcl_FindHashEntry(&needXFreeFontListTable, (char *)list);
    if (entry != NULL) {
#ifdef USE_OWN_XLSFONT
      TkUnixXFreeFontNames(list);
#else
      XFreeFontNames(list);
#endif /* USE_OWN_XLSFONT */
      Tcl_DeleteHashEntry(entry);
    } else {
      ckfree(list);
    }
    return 1;
}


static int
GetPixelSizeFromFontname(name)
    char *name;
{
    int i;
    char *str = name;
    char buf[16];
    int ret = 0;

    for (i = 0; i < XLFD_PIXEL_SIZE; i++) {
      str = strchr(str + 1, '-');
      if (str == NULL) break;
    }
    if (str != NULL) {
      str++;
      if (*str != 0) {
          for (i = 0; i < 16; i++) {
            if (str[i] == '-' || str[i] == 0) break;
            buf[i] = str[i];
          }
          buf[i] = 0;
          ret = atoi(buf);
      }
    }
    return ret;
}


#define CHARSET_MASK    0x07
#define IS_ISO8859      0x01
#define IS_JISX0201     0x02
#define IS_JISX0208     0x04
#define IS_OTHER  0x08

static int
GetCharsetFromFontname(kName)
    char *kName;
{
    char *tmp = strrchr(kName, '-');
    if (tmp != NULL) {
      tmp--;
      while (*tmp != 0 && *tmp != '-') {
          tmp--;
      }
      if (tmp != NULL) {
          tmp++;
          if (strncasecmp(tmp, "iso8859", 7) == 0) {
            return IS_ISO8859;
          } else if (strncasecmp(tmp, "jisx0201.1976", 13) == 0) {
            return IS_JISX0201;
          } else if (strncasecmp(tmp, "jisx0208.1983", 13) == 0) {
            return IS_JISX0208;
          }
      }
    }
    return IS_OTHER;
}


#ifdef XOM_CHECK
static void
DrawDummyWithFontSet(tkwin, fontSet)
    Tk_Window tkwin;
    XFontSet fontSet;
{
    static int dummyInited = 0;
    static GC gc = None;
    static GC clearGC = None;
    static Window w = None;
    static Pixmap p = None;
    static int screen;
    static XGCValues xgc;
    static int yPos = 30;
    char str[] = "01234 abcde (XFontSet I=<(%F%9%HMQ$NJ8;zNs)";
    
    if (dummyInited == 0) {
      Display *dpy = Tk_Display(tkwin);
      screen = DefaultScreen(dpy);
      w = XCreateSimpleWindow(dpy, RootWindow(dpy, screen), 0, 0, 400, 300, 2,
                        WhitePixel(dpy, screen),
                        WhitePixel(dpy, screen));
      p = XCreatePixmap(dpy, RootWindow(dpy, screen), 600, 300, DefaultDepth(dpy, screen));

      gc = XCreateGC(dpy, RootWindow(dpy, screen), 0, &xgc);
      XSetForeground(dpy, gc, BlackPixel(dpy, screen));
      XSetBackground(dpy, gc, WhitePixel(dpy, screen));
      XSetFunction(dpy, gc, GXcopy);

      clearGC = XCreateGC(dpy, RootWindow(dpy, screen), 0, &xgc);
      XSetFunction(dpy, clearGC, GXcopy);
      XSetLineAttributes(dpy, clearGC, 4096, LineSolid, CapButt, JoinBevel);
      XSetPlaneMask(dpy, clearGC, AllPlanes);
      XSetForeground(dpy, clearGC, WhitePixel(dpy, screen));
      XSetBackground(dpy, clearGC, WhitePixel(dpy, screen));

      XMapWindow(dpy, w);
      XSync(dpy, False);
      XDrawLine(dpy, p, clearGC, 0, 150, 400, 150);
                        
      dummyInited = 1;
   }

    XClearWindow(Tk_Display(tkwin), w);
    XmbDrawString(Tk_Display(tkwin), p, fontSet, gc, 5, yPos, str, strlen(str));
    XSetWindowBackgroundPixmap(Tk_Display(tkwin), w, p);
    yPos += 30;
    if (yPos >= 300) {
      XClearWindow(Tk_Display(tkwin), w);
      XDrawLine(Tk_Display(tkwin), p, clearGC, 0, 150, 400, 150);
      yPos = 30;
    }
}
#endif /* XOM_CHECK */


XFontSet
TkpCreateFontSet(tkwin, fontlist, aName, kName)
    Tk_Window tkwin;
    char *fontlist;
    char *aName;
    char *kName;
{
    XFontSet newFont = NULL;
    TkpFontSetCache *newCache;
    int new;
    Tcl_HashEntry *entry = NULL;
    Tcl_HashEntry *keyEntry = NULL;
    TkpFontSetCacheKey key;

    key.name = Tk_GetUid(fontlist);
    key.dpy = Tk_Display(tkwin);
    entry = Tcl_CreateHashEntry(&xFontSetCacheTable, (char *)&key, &new);
    if (new == 0) {
        newCache = (TkpFontSetCache *)Tcl_GetHashValue(entry);
        newCache->refCount++;
        return newCache->xFontSet;
    }

    {
      char **ml;
      int mc;
      char *ds;
      char fBuf[4096];
      int pix;
      int dpi;
      char *missingCharset = NULL;
      int mCharset = CHARSET_MASK;
      int retry = 0;

      mCharset &= ~(GetCharsetFromFontname(aName));
      mCharset &= ~(GetCharsetFromFontname(kName));
      mCharset &= CHARSET_MASK;

#ifdef FONTSETCACHE_DEBUG
      fprintf(stderr, "fSetCacheDebug: loading '%s'.....", key.name);
#endif /* FONTSETCACHE_DEBUG */

      sprintf(fBuf, "%s, %s", aName, kName);

        doCreate:
      newFont = XCreateFontSet(key.dpy, fBuf, &ml, &mc, &ds);
      if (mc > 0) {
          XFreeStringList(ml);
      }
      if (newFont != NULL) {
          goto createOK;
      }

      switch (retry) {
          case 0: {
            /*
             * Well, by specification, XCreateFontSet() should
             * return valid XFontSet and missing charset, but it didn't.
             * Mayhaps one more charset (jisx0201 or iso8859) is needed.
             */
            retry++;

            pix = GetPixelSizeFromFontname(kName);
            dpi = TkpGetDPI(tkwin, NULL);

            if (mCharset == IS_ISO8859) {
                missingCharset = "ISO8859-1";
            } else if (mCharset == IS_JISX0201) {
                missingCharset = "JISX0201.1976-0";
            } else if (mCharset == IS_JISX0208) {
                missingCharset = "JISX0208.1983-0";
            }
      
            sprintf(fBuf, "%s, %s, -*-fixed-medium-r-normal-*-%d-*-%d-%d-*-*-%s",
                  aName, kName, pix, dpi, dpi, missingCharset);
            break;
          }

          case 1: {
            retry++;
            sprintf(fBuf, "%s, %s, -*-fixed-medium-r-normal-*-%d-*-*-*-*-*-%s",
                  aName, kName, pix, missingCharset);
            break;
          }

          case 2: {
            retry++;
            /*
             * Try the easyest pattern.
             */
            sprintf(fBuf, "-*-fixed-medium-r-normal-*-%d-*-*-*-*-*-*-*", pix);
            break;
          }

          case 3: {
            retry++;
            /*
             * sucks.
             */
            Tcl_DeleteHashEntry(entry);
            return NULL;
            break;
          }
      }
      goto doCreate;

        createOK:
      newCache = (TkpFontSetCache *)ckalloc(sizeof(TkpFontSetCache));
      newCache->name = key.name;
      newCache->xFontSet = newFont;
      newCache->refCount = 1;
      newCache->entry = entry;
      
      keyEntry = Tcl_CreateHashEntry(&xFontSetKeyTable, (char *)newFont, &new);
      if (new == 0) {
          panic("display and fontset name is already stored in cache!");
      }
      Tcl_SetHashValue(entry, (ClientData)newCache);
      Tcl_SetHashValue(keyEntry, (ClientData)newCache);
#ifdef  FONTSETCACHE_DEBUG
      fprintf(stderr, "done, %s.\n", (newFont != NULL) ? "ok" : "fail");
#endif /* FONTSETCACHE_DEBUG */

#ifdef XOM_CHECK
      DrawDummyWithFontSet(tkwin, newFont);
#endif /* XOM_CHECK */
    }

    return newFont;
}


void
TkpFreeFontSet(tkwin, xFontSet)
    Tk_Window tkwin;
    XFontSet xFontSet;
{
    Tcl_HashEntry *keyEntry = Tcl_FindHashEntry(&xFontSetKeyTable, (char *)xFontSet);
    TkpFontSetCache *val;

    if (keyEntry == NULL) {
        panic("uncached font about to free.");
    }
    val = (TkpFontSetCache *)Tcl_GetHashValue(keyEntry);
    val->refCount--;
    if (val->refCount == 0) {
      XFreeFontSet(Tk_Display(tkwin), val->xFontSet);
      Tcl_DeleteHashEntry(val->entry);
      Tcl_DeleteHashEntry(keyEntry);
#ifdef FONTSETCACHE_DEBUG
      fprintf(stderr, "fSetCacheDebug: free '%s' 0x%08x\n",
            val->name, val->xFontSet);
#endif /* FONTSETCACHE_DEBUG */
      ckfree((char *)val);
    }
}


static int
IncrFontCacheRefCount(fontCache)
    TkpFontCache *fontCache;
{
    fontCache->refCount++;
    if (fontCache->maxRef < fontCache->refCount) {
      fontCache->maxRef = fontCache->refCount;
    }
    return fontCache->refCount;
}


static TkpFontNameAliasRec *
CreateFontNameAlias(entry)
    Tcl_HashEntry *entry;
{
    TkpFontNameAliasRec *ret = (TkpFontNameAliasRec *)ckalloc(sizeof(TkpFontNameAliasRec));
    ret->entry = entry;
    ret->next = NULL;
    return ret;
}


static void
AddFontNameAlias(propCache, name)
    TkpFontCache *propCache;
    Tk_Uid name;
{
    Tcl_HashEntry *aEntry = NULL;
    int aNew = 0;
    TkpFontCacheKey aKey;
    TkpFontNameAliasRec *aNameRec = NULL;

    aKey.dpy = propCache->dpy;
    aKey.name = name;
    aEntry = Tcl_CreateHashEntry(&xFontCacheTable, (char *)&aKey, &aNew);
    if (aNew == 0) {
      panic("Alias name is already cached.");
    }
    aNameRec = CreateFontNameAlias(aEntry);
    propCache->aTail->next = aNameRec;
    propCache->aTail = aNameRec;

#ifdef FONTCACHE_DEBUG    
    {
      TkpFontNameAliasRec *tmp = propCache->alias;
      TkpFontCacheKey *key;
      while (tmp != NULL) {
          key = (TkpFontCacheKey *)Tcl_GetHashKey(&xFontCacheTable, tmp->entry);
          fprintf(stderr, "\tdebug: alias entry '%s'\n", key->name);
          tmp = tmp->next;
      }
      fprintf(stderr, "\n");
    }
#endif /* FONTCACHE_DEBUG */

    Tcl_SetHashValue(aEntry, (ClientData)propCache);
}


static Tk_Uid
FontnameLower(name)
    char *name;
{
    char buf[1024];
    char *pBuf = buf;

    while (*name != 0) {
      if (isalpha(*name)) {
          *pBuf = tolower(*name);
      } else {
          *pBuf = *name;
      }
      pBuf++;
      name++;
    }
    *pBuf = 0;
    
    return Tk_GetUid(buf);
}


XFontStruct *
#ifdef USE_OWN_XLQFONT
#if NeedFunctionPrototypes
XLoadQueryFont(
    Display *dpy,
    _Xconst char *name
)
#else
XLoadQueryFont(dpy, name)
    Display *dpy;
    _Xconst char *name;
#endif /* NeedFunctionPrototypes */
#else
TkpLoadQueryFont(dpy, name)
    Display *dpy;
    char *name;
#endif /* USE_OWN_XLQFONT */
{
    XFontStruct *newFont = NULL;
    TkpFontCache *newCache = NULL;
    Tcl_HashEntry *gnEntry = NULL;
    Tk_Uid givenName = FontnameLower(name);
    TkpFontCacheKey key;
    int nHyphn = 0;
    int nAsta = 0;
    int hasSpace = (strchr(givenName, ' ') != NULL) ? 1 : 0;
    char *tmp;

    if ((givenName[0] != '*' &&
       givenName[0] != '-' &&
       hasSpace == 1) ||
      !(isprint(givenName[0]))) {
      return NULL;
    }

    key.name = givenName;
    key.dpy = dpy;

    gnEntry = Tcl_FindHashEntry(&xFontCacheTable, (char *)&key);
    if (gnEntry != NULL) {
      newCache = (TkpFontCache *)Tcl_GetHashValue(gnEntry);
      IncrFontCacheRefCount(newCache);
      return newCache->xFontPtr;
    }

    tmp = givenName;
    while ((tmp = strchr(tmp, '-')) != NULL) {
      tmp++;
      nHyphn++;
    }
    tmp = givenName;
    while ((tmp = strchr(tmp, '*')) != NULL) {
      tmp++;
      nAsta++;
    }
    
    if (nHyphn >= 13 && nAsta <= 10) {
      char **candNames = NULL;
      int numCand = 0;

#ifdef USE_OWN_XLSFONT
      candNames = XListFonts(dpy, givenName, 100000, &numCand);
#else
      candNames = TkpListFonts(dpy, givenName, 100000, &numCand);
#endif /* USE_OWN_XLSFONT */
      if (numCand > 0) {
          int i;
          Tcl_HashEntry *cEntry;
          for (i = 0; i < numCand; i++) {
            key.name = FontnameLower(candNames[i]);
            cEntry = Tcl_FindHashEntry(&xFontCacheTable, (char *)&key);
            if (cEntry != NULL) {
                newCache = (TkpFontCache *)Tcl_GetHashValue(cEntry);
                AddFontNameAlias(newCache, givenName);
                IncrFontCacheRefCount(newCache);
#ifdef USE_OWN_XLSFONT
                XFreeFontNames(candNames);
#else
                TkpFreeFontNames(candNames);
#endif /* USE_OWN_XLSFONT */
                return newCache->xFontPtr;
            }
          }
#ifdef USE_OWN_XLSFONT
          XFreeFontNames(candNames);
#else
          TkpFreeFontNames(candNames);
#endif /* USE_OWN_XLSFONT */
      }
    }

#ifdef USE_OWN_XLQFONT
    if ((newFont = TkUnixXLoadQueryFont(dpy, givenName)) != NULL) {
#else
    if ((newFont = XLoadQueryFont(dpy, givenName)) != NULL) {
#endif /* USE_OWN_XLQFONT */
      unsigned long atom;
      char *propName;
      Tk_Uid pName;
      int pnNew = 0;
      Tcl_HashEntry *pnEntry = NULL;

      /*
       * Check whether the property name of the font is already cached or not.
       */
      if (XGetFontProperty(newFont, XA_FONT, &atom) != True) {
          panic("can't get font property name.");
      }
      propName = XGetAtomName(dpy, atom);
#ifdef CHECK_XTT
      pName = FontnameLower(NormalizeXLFD(propName));
#else
      pName = FontnameLower(propName);
#endif /* CHECK_XTT */
      XFree(propName);
      
      key.name = pName;
      key.dpy = dpy;
      pnEntry = Tcl_CreateHashEntry(&xFontCacheTable, (char *)&key, &pnNew);
      if (pnNew == 1) {
          /*
           * Add an entry for property name of the font.
           */
          Tcl_HashEntry *keyEntry = NULL;
          int keyNew = 0;
          newCache = (TkpFontCache *)ckalloc(sizeof(TkpFontCache));
          newCache->name = pName;
          newCache->dpy = dpy;
          newCache->xFontPtr = newFont;
          newCache->refCount = 1;
          newCache->maxRef = 1;
          newCache->aTail = newCache->alias = CreateFontNameAlias(pnEntry);
          newCache->toBeFree = 0;
          Tcl_SetHashValue(pnEntry, (ClientData)newCache);
          
          keyEntry = Tcl_CreateHashEntry(&xFontKeyTable, (char *)newFont, &keyNew);
          if (keyNew == 0) {
            panic("display and fontname is already stored in cache!");
          }
          Tcl_SetHashValue(keyEntry, (ClientData)newCache);

#ifdef FONTCACHE_DEBUG
          fprintf(stderr, "fCacheDebug: load '%s' 0x%08x\n",
                pName, newFont);
#endif /* FONTCACHE_DEBUG */

          if (givenName != pName) {
            /*
             * Add an entry for given name of the font.
             */
            AddFontNameAlias(newCache, givenName);
#ifdef FONTCACHE_DEBUG
            fprintf(stderr, "fCacheDebug: load '%s' 0x%08x (only entry)\n",
                  givenName, newFont);
#endif /* FONTCACHE_DEBUG */
          }
          
          return newFont;
      } else /* get prop entry */ {
          /*
           * Cached entry of the font (property name) is found.
           * Add an entry for given name of the font and return font
           * struct of property name.
           */

          newCache = (TkpFontCache *)Tcl_GetHashValue(pnEntry);

          if (newCache->xFontPtr != newFont) {
#ifdef USE_OWN_XLQFONT
            TkUnixXFreeFont(dpy, newFont);
#else
            XFreeFont(dpy, newFont);
#endif /* USE_OWN_XLQFONT */
          }
#ifdef FONTCACHE_DEBUG
          fprintf(stderr, "fCacheDebug: load '%s' 0x%08x (only entry)\n",
                givenName, newFont);
#endif /* FONTCACHE_DEBUG */
          AddFontNameAlias(newCache, givenName);
          IncrFontCacheRefCount(newCache);
          return newCache->xFontPtr;
      }
    }

    return NULL;
}


static void
DeleteFontCache(fontCache)
    TkpFontCache *fontCache;
{
    TkpFontNameAliasRec *alias, *next;
    TkpFontCacheKey *tmp;

    if (fontCache->refCount > 0) {
      panic("Refernced font cache is about to free");
    }
    alias = fontCache->alias;
    if (alias == NULL) {
      panic("Font cache has no name");
    }
    if (alias->entry == NULL) {
      panic("Font cache has no font cache entry");
    }

    while (alias != NULL) {
      tmp = (TkpFontCacheKey *)Tcl_GetHashKey(&xFontCacheTable, alias->entry);
      Tcl_DeleteHashEntry(alias->entry);
      next = alias->next;
      ckfree(alias);
      alias = next;
    }
    
#ifdef USE_OWN_XLQFONT
    TkUnixXFreeFont(fontCache->dpy, fontCache->xFontPtr);
#else
    XFreeFont(fontCache->dpy, fontCache->xFontPtr);
#endif /* USE_OWN_XLQFONT */

    ckfree(fontCache);
}


#ifdef USE_OWN_XLQFONT
int
#if NeedFunctionPrototypes
XFreeFont(
    Display *dpy,
    XFontStruct *xFontPtr
)
#else
XFreeFont(dpy, xFontPtr)
    Display *dpy;
    XFontStruct *xFontPtr;
#endif /* NeedFunctionPrototypes */
#else
void
TkpFreeFont(dpy, xFontPtr)
    Display *dpy;
    XFontStruct *xFontPtr;
#endif /* USE_OWN_XLQFONT */
{
    Tcl_HashEntry *keyEntry = Tcl_FindHashEntry(&xFontKeyTable, (char *)xFontPtr);
    TkpFontCache *val;

    if (keyEntry == NULL) {
#ifdef  FONTCACHE_DEBUG
      unsigned long atom;
      Tcl_HashEntry *entry;
      char *name;
      Tk_Uid pName;
      TkpFontCacheKey key;

      if (XGetFontProperty(xFontPtr, XA_FONT, &atom) != True) {
          panic("uncached font about to free, can't get property.");
      }
      name = XGetAtomName(dpy, atom);
      pName = FontnameLower(NormalizeXLFD(name));

      XFree(name);

      fprintf(stderr, "debug: uncached '%s' free.. \n", pName);

      key.name = pName;
      key.dpy = dpy;
      entry = Tcl_FindHashEntry(&xFontCacheTable, (char *)&key);
      if (entry == NULL) {
          fprintf(stderr, "debug: OK, not in hash.\n");
      } else {
          fprintf(stderr, "debug: ??? in hash !!\n");
          val = Tcl_GetHashValue(entry);
          fprintf(stderr, "debug: in hash '%s', 0x%08x\n", val->name, val->xFontPtr);
      }
#endif /* FONTCACHE_DEBUG */
      panic("uncached font about to free.");
    }
    val = (TkpFontCache *)Tcl_GetHashValue(keyEntry);
    val->refCount--;
    if (val->refCount <= 0) {
      if (val->maxRef > 1) {
#ifdef FONTCACHE_DEBUG
          fprintf(stderr, "fCacheDebug: free '%s' 0x%08x\n",
                val->name, val->xFontPtr);
#endif /* FONTCACHE_DEBUG */
          DeleteFontCache(val);
          Tcl_DeleteHashEntry(keyEntry);
      } else {
          val->refCount = 0;
      }
    }
#ifdef USE_OWN_XLQFONT
    return 1;
#endif /* USE_OWN_XLQFONT */
}


static void
DumpFontCache(dpy, resultPtr)
    Display *dpy;
    Tcl_Obj *resultPtr;
{
    Tcl_HashSearch search;
    Tcl_HashEntry *entry = NULL;
    TkpFontCache *fCache = NULL;
    TkpFontCacheKey *key = NULL;
    char buf[4096];
    
    for (entry = Tcl_FirstHashEntry(&xFontCacheTable, &search);
       entry != NULL;
       entry = Tcl_NextHashEntry(&search)) {
      fCache = (TkpFontCache *)Tcl_GetHashValue(entry);
      if (fCache == NULL) {
          panic("invalid cache data exists.");
      }
      key = (TkpFontCacheKey *)Tcl_GetHashKey(&xFontCacheTable, entry);
      if (key == NULL) {
          panic("invalid cache key exists.");
      }
      if (dpy == NULL || key->dpy == dpy) {
          sprintf(buf, "{{%s} 0x%08x %d} ", key->name, fCache->xFontPtr, fCache->refCount);
          Tcl_AppendStringsToObj(resultPtr, buf, NULL);
      }
    }
}


int
TkpFreeFontCache(interp, tkwin, doClear)
    Tcl_Interp *interp;
    Tk_Window tkwin;
    int doClear;
{
    Display *dpy = NULL;
    Tcl_HashSearch search;
    Tcl_HashEntry *entry = NULL;
    TkpFontCache *fCache = NULL;
    Tcl_Obj *resultPtr = NULL;
    int deleteCount = 0;

    if (interp != NULL) {
      resultPtr = Tcl_GetObjResult(interp);
    }
    if (tkwin != NULL) {
      dpy = Tk_Display(tkwin);
    }

    if (doClear == -1) {
      if (resultPtr != NULL) {
          DumpFontCache(dpy, resultPtr);
      }
      return TCL_OK;
    }

    for (entry = Tcl_FirstHashEntry(&xFontCacheTable, &search);
       entry != NULL;
       entry = Tcl_NextHashEntry(&search)) {

      if ((fCache = (TkpFontCache *)Tcl_GetHashValue(entry)) == NULL) {
          panic("Invalid font cache");
      }

      if ((dpy == NULL || fCache->dpy == dpy) && fCache->refCount <= 0) {
          TkpFontCacheKey *key = (TkpFontCacheKey *)Tcl_GetHashKey(&xFontCacheTable, entry);

          if (resultPtr != NULL) {
            Tcl_AppendStringsToObj(resultPtr, "{", key->name, "} ", NULL);
          }

          if (doClear == 1) {
            if (fCache->name == key->name) {
                fCache->toBeFree = 1;
                fCache->maxRef = INT_MAX;
                deleteCount++;
            }
#ifdef FONTCACHE_DEBUG
            fprintf(stderr, "fCacheDebug: free '%s' 0x%08x (in cache free)\n",
                  key->name, fCache->xFontPtr);
#endif /* FONTCACHE_DEBUG */
          }
      }
    }

    if (doClear == 1 && deleteCount > 0) {
      TkpFontCache **del = (TkpFontCache **)ckalloc(sizeof(TkpFontCache *) * deleteCount);
      int n = 0;
      int i;
      TkpFontCacheKey *key;

      for (entry = Tcl_FirstHashEntry(&xFontCacheTable, &search);
           entry != NULL;
           entry = Tcl_NextHashEntry(&search)) {

          /*
           * Only entries that have property name MUST be searched.
           */
          fCache = (TkpFontCache *)Tcl_GetHashValue(entry);
          key = (TkpFontCacheKey *)Tcl_GetHashKey(&xFontCacheTable, entry);
          if (fCache->toBeFree == 1 &&
            fCache->name == key->name) {
            del[n] = fCache;
            n++;
          }
      }

      if (n != deleteCount) {
          panic("# of fonts to be delete is invalid.");
      }

      for (i = 0; i < n; i++) {
#ifdef USE_OWN_XLQFONT
          XFreeFont(del[i]->dpy, del[i]->xFontPtr);
#else
          TkpFreeFont(del[i]->dpy, del[i]->xFontPtr);
#endif /* USE_OWN_XLQFONT */
      }

      ckfree(del);
    }
    
    return TCL_OK;
}


Tk_Uid
TkpGetFontnameFromFontStruct(xFontPtr)
    XFontStruct *xFontPtr;
{
    Tcl_HashEntry *keyEntry;
    TkpFontCache *val;

    if (xFontPtr == NULL) {
      panic("font struct null.");
    }
    keyEntry = Tcl_FindHashEntry(&xFontKeyTable, (char *)xFontPtr);
    if (keyEntry == NULL) {
      panic("uncached font reference.");
    }
    val = (TkpFontCache *)Tcl_GetHashValue(keyEntry);
    return val->name;
}
#endif /* KANJI */

Generated by  Doxygen 1.6.0   Back to index