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

tkUnixFont.c

/*
 * tkUnixFont.c --
 *
 *    Contains the Unix implementation of the platform-independant
 *    font package interface.
 *
 * Copyright (c) 1996 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tkUnixFont.c,v 1.3 1998/09/14 18:23:57 stanton Exp $
 */
 
#include "tkPort.h"
#include "tkInt.h"
#include "tkUnixInt.h"

#include "tkFont.h"

#ifndef ABS
#define ABS(n)    (((n) < 0) ? -(n) : (n))
#endif
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif

/*
 * The following structure represents Unix's implementation of a font.
 */
 
typedef struct UnixFont {
    TkFont font;        /* Stuff used by generic font package.  Must
                         * be first in structure. */
    Display *display;         /* The display to which font belongs. */
    XFontStruct *fontStructPtr;     /* X information about font. */
#ifdef KANJI
    char *types;
    unsigned char *widths;
#else
    char types[256];          /* Array giving types of all characters in
                         * the font, used when displaying control
                         * characters.  See below for definition. */
    int widths[256];          /* Array giving widths of all possible
                         * characters in the font. */
#endif /* KANJI */
    int underlinePos;         /* Offset from baseline to origin of
                         * underline bar (used for simulating a native
                         * underlined font). */
    int barHeight;            /* Height of underline or overstrike bar
                         * (used for simulating a native underlined or
                         * strikeout font). */
#ifdef KANJI
#ifdef UNIXFONT_DEBUG
    int isFreed;
#endif /* UNIXFONT_DEBUG */
#endif /* KANJI */
} UnixFont;

/*
 * Possible values for entries in the "types" field in a UnixFont structure,
 * which classifies the types of all characters in the given font.  This
 * information is used when measuring and displaying characters.
 *
 * NORMAL:        Standard character.
 * REPLACE:       This character doesn't print:  instead of
 *                displaying character, display a replacement
 *                sequence like "\n" (for those characters where
 *                ANSI C defines such a sequence) or a sequence
 *                of the form "\xdd" where dd is the hex equivalent
 *                of the character.
 * SKIP:          Don't display anything for this character.  This
 *                is only used where the font doesn't contain
 *                all the characters needed to generate
 *                replacement sequences.
 */ 

#define NORMAL          0
#define REPLACE         1
#define SKIP            2
#ifdef KANJI
/*
 * new character type for Kanji:
 *      WRAPUP: like NORMAL, but needs special treatment
 *              for word wrapping.  This character should not
 *              appear at the beginning of a line.
 *              (something like '.' or ',')
 */
#define WRAPUP          3
#endif /* KANJI */

/*
 * Characters used when displaying control sequences.
 */

static char hexChars[] = "0123456789abcdefxtnvr\\";

/*
 * The following table maps some control characters to sequences like '\n'
 * rather than '\x10'.  A zero entry in the table means no such mapping
 * exists, and the table only maps characters less than 0x10.
 */

static char mapChars[] = {
    0, 0, 0, 0, 0, 0, 0,
    'a', 'b', 't', 'n', 'v', 'f', 'r',
    0
};


static UnixFont * AllocFont _ANSI_ARGS_((TkFont *tkFontPtr,
                      Tk_Window tkwin, XFontStruct *fontStructPtr,
                      CONST char *fontName));
static void       DrawChars _ANSI_ARGS_((Display *display,
                      Drawable drawable, GC gc, UnixFont *fontPtr,
                      CONST char *source, int numChars, int x,
                      int y));
#ifdef KANJI
static int        DrawWChars _ANSI_ARGS_((Display *display,
                      Drawable drawable, GC gc, UnixFont *fontPtr,
                      CONST wchar *source, int numChars, int x,
                      int y));
#endif /* KANJI */
static int        GetControlCharSubst _ANSI_ARGS_((int c, char buf[4]));

#ifdef KANJI
/*
 * TkpGetDPI
 *    return helpful information to determine which (100dpi/75dpi)
 *    font path's font should be used.
 */
int
TkpGetDPI(tkwin, realDPIRet)
    Tk_Window tkwin;
    double *realDPIRet;
{
    int d100, d75;
    double rDPI = ((double)(WidthOfScreen(Tk_Screen(tkwin))) /
                (double)(WidthMMOfScreen(Tk_Screen(tkwin))) * 25.4);
    int dpi = (int)(rDPI + .5);

    d100 = 100 - dpi;
    if (d100 < 0) {
      d100 = -d100;
    }
    d75 = 75 -dpi;
    if (d75 < 0) {
      d75 = -d75;
    }
    if (realDPIRet != NULL) {
      *realDPIRet = rDPI;
    }
    return (d100 < d75) ? 100 : 75;
}


int
TkpConvertPointToPixel(tkwin, pointsize)
    Tk_Window tkwin;
    int pointsize;
{
    double rDPI = ((double)(WidthOfScreen(Tk_Screen(tkwin))) /
                (double)(WidthMMOfScreen(Tk_Screen(tkwin))) * 25.4);
    double ret = (double)(pointsize) * rDPI / 72.0 + 0.5;
    return (int)ret;
}


int
TkpConvertPixelToPoint(tkwin, pixelsize)
    Tk_Window tkwin;
    int pixelsize;
{
    /* 72.0 : pointsize = rDPI : pixelsize */
    double rDPI = ((double)(WidthOfScreen(Tk_Screen(tkwin))) /
                (double)(WidthMMOfScreen(Tk_Screen(tkwin))) * 25.4);
    double ret = (double)(pixelsize) * 72.0 / rDPI + 0.5;
    return (int)ret;
}


Tk_Uid 
TkpGetFontPropertyName(tkwin, xFontPtr)
    Tk_Window tkwin;
    XFontStruct *xFontPtr;
{
    unsigned long val;
    if (XGetFontProperty(xFontPtr, XA_FONT, &val) && val != 0) {
#ifdef CHECK_XTT
      Tk_Uid aName = Tk_GetUid(Tk_GetAtomName(tkwin, val));
      Tk_Uid sName = NormalizeXLFD(aName);
      if (aName == sName) {
          return aName;
      } else {
          return sName;
      }
#else
      return Tk_GetUid(Tk_GetAtomName(tkwin, val));
#endif /* CHECK_XTT */
    }
    return NULL;
}


Tk_Uid
TkpGetFontPropertyNameFromTkFont(tkwin, tkFont)
    Tk_Window tkwin;
    Tk_Font tkFont;
{
    return TkpGetFontPropertyName(tkwin, ((UnixFont *)tkFont)->fontStructPtr);
}

#endif /* KANJI */

/*
 *---------------------------------------------------------------------------
 *
 * TkpGetNativeFont --
 *
 *    Map a platform-specific native font name to a TkFont.
 *
 * Results:
 *    The return value is a pointer to a TkFont that represents the
 *    native font.  If a native font by the given name could not be
 *    found, the return value is NULL.  
 *
 *    Every call to this procedure returns a new TkFont structure,
 *    even if the name has already been seen before.  The caller should
 *    call TkpDeleteFont() when the font is no longer needed.
 *
 *    The caller is responsible for initializing the memory associated
 *    with the generic TkFont when this function returns and releasing
 *    the contents of the generic TkFont before calling TkpDeleteFont().
 *
 * Side effects:
 *    None.
 *
 *---------------------------------------------------------------------------
 */

TkFont *
TkpGetNativeFont(tkwin, name)
    Tk_Window tkwin;          /* For display where font will be used. */
    CONST char *name;         /* Platform-specific font name. */
{
    XFontStruct *fontStructPtr;
    fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), name);
    if (fontStructPtr == NULL) {
      return NULL;
    }
    return (TkFont *) AllocFont(NULL, tkwin, fontStructPtr, name);
}

/*
 *---------------------------------------------------------------------------
 *
 * TkpGetFontFromAttributes -- 
 *
 *    Given a desired set of attributes for a font, find a font with
 *    the closest matching attributes.
 *
 * Results:
 *    The return value is a pointer to a TkFont that represents the
 *    font with the desired attributes.  If a font with the desired
 *    attributes could not be constructed, some other font will be
 *    substituted automatically.
 *
 *    Every call to this procedure returns a new TkFont structure,
 *    even if the specified attributes have already been seen before.
 *    The caller should call TkpDeleteFont() to free the platform-
 *    specific data when the font is no longer needed.  
 *
 *    The caller is responsible for initializing the memory associated
 *    with the generic TkFont when this function returns and releasing
 *    the contents of the generic TkFont before calling TkpDeleteFont().
 *
 * Side effects:
 *    None.
 *
 *---------------------------------------------------------------------------
 */
TkFont *
TkpGetFontFromAttributes(tkFontPtr, tkwin, faPtr)
    TkFont *tkFontPtr;        /* If non-NULL, store the information in
                         * this existing TkFont structure, rather than
                         * allocating a new structure to hold the
                         * font; the existing contents of the font
                         * will be released.  If NULL, a new TkFont
                         * structure is allocated. */
    Tk_Window tkwin;          /* For display where font will be used. */
    CONST TkFontAttributes *faPtr;  /* Set of attributes to match. */
{
    int numNames, score, i, scaleable, pixelsize, xaPixelsize;
    int bestIdx, bestScore, bestScaleableIdx, bestScaleableScore;
    TkXLFDAttributes xa;    
    char buf[256];
    UnixFont *fontPtr;
    char **nameList;
    XFontStruct *fontStructPtr;
    CONST char *fmt, *family;
#ifndef KANJI
    double d;
#endif /* !KANJI */
#ifdef KANJI
    char *charset;
    int dpi;
    double realDPI;
    int onceAgain = 0;
    Tcl_HashEntry *entry = NULL;
    int new = 0;
    char orgTryName[256];
    int bufLen = 0;
    int careDPI = 0;
    extern Tcl_HashTable xFindFontTable;
    int doExactLoad = 0;

    fontPtr = (UnixFont *)tkFontPtr;

    if (faPtr->fontType == TK_FONT_COMPOUND) {
      TkWindow *winPtr = (TkWindow *)tkwin;
      if (fontPtr == (UnixFont *)NULL) {
          fontPtr = (UnixFont *)ckalloc(sizeof(UnixFont));
          tkFontPtr = (TkFont *)fontPtr;
          memset((VOID *)fontPtr, 0, sizeof(UnixFont));
          memcpy((VOID *)&(fontPtr->font.fa), (VOID *)faPtr,
               sizeof(TkFontAttributes));
      }
      if (fontPtr->font.asciiFontPtr == NULL) {
          fontPtr->font.asciiFontPtr = (TkFont *)Tk_GetFont(winPtr->mainPtr->interp,
                                                tkwin, faPtr->asciiFontName);
          Tk_AddCompoundParent((Tk_Font)(fontPtr->font.asciiFontPtr), (Tk_Font)fontPtr);
      }
      if (fontPtr->font.kanjiFontPtr == NULL) {
          fontPtr->font.kanjiFontPtr = (TkFont *)Tk_GetFont(winPtr->mainPtr->interp,
                                                tkwin, faPtr->kanjiFontName);
          Tk_AddCompoundParent((Tk_Font)(fontPtr->font.kanjiFontPtr), (Tk_Font)fontPtr);
      }

      fontPtr->display = ((UnixFont *)(fontPtr->font.asciiFontPtr))->display;
      fontPtr->fontStructPtr = ((UnixFont *)(fontPtr->font.asciiFontPtr))->fontStructPtr;

      TkpUpdateCompoundFont((TkFont *)fontPtr, faPtr);

      return (TkFont *)fontPtr;
    }

    orgTryName[0] = 0;
    dpi = TkpGetDPI(tkwin, &realDPI);

    charset = faPtr->charset;
    if (charset == NULL) {
      charset = "iso8859";
    }
#endif /* KANJI */

    family = faPtr->family;
    if (family == NULL) {
#ifdef KANJI
      family = "fixed";
#else
      family = "*";
#endif /* KANJI */
    }


#ifdef KANJI
    if (faPtr->pointsize > 0) {
      pixelsize = TkpConvertPointToPixel(tkwin, faPtr->pointsize);
    } else {
      pixelsize = -faPtr->pointsize;
    }
#else
    pixelsize = -faPtr->pointsize;
    if (pixelsize < 0) {
        d = -pixelsize * 25.4 / 72;
      d *= WidthOfScreen(Tk_Screen(tkwin));
      d /= WidthMMOfScreen(Tk_Screen(tkwin));
      d += 0.5;
        pixelsize = (int) d;
    }
#endif /* KANJI */
    /*
     * Replace the standard Windows and Mac family names with the names that
     * X likes.
     */

    if ((strcasecmp("Times New Roman", family) == 0)
          || (strcasecmp("New York", family) == 0)) {
      family = "Times";
    } else if ((strcasecmp("Courier New", family) == 0)
          || (strcasecmp("Monaco", family) == 0)) {
      family = "Courier";
    } else if ((strcasecmp("Arial", family) == 0)
          || (strcasecmp("Geneva", family) == 0)) {
      family = "Helvetica";
    }

#ifndef KANJI
    /*
     * First try for the Q&D exact match.  
     */

#if 0
    sprintf(buf, "-*-%.200s-%s-%c-normal-*-*-%d-*-*-*-*-iso8859-1", family,
          ((faPtr->weight > TK_FW_NORMAL) ? "bold" : "medium"),
          ((faPtr->slant == TK_FS_ROMAN) ? 'r' :
                (faPtr->slant == TK_FS_ITALIC) ? 'i' : 'o'),
          faPtr->pointsize * 10);
    fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), buf);
#else
    fontStructPtr = NULL;
#endif

    if (fontStructPtr != NULL) {
      goto end;
    }
    /*
     * Couldn't find exact match.  Now fall back to other available
     * physical fonts.  
     */
#endif /* !KANJI */

#ifdef KANJI
    careDPI = 1;
    fontStructPtr = NULL;
    if (pixelsize > 0 && faPtr->foundry != NULL) {
      /* Load exect. */
      fmt = "-%.200s-%.200s-%s-%c-%s-*-%d-*-%d-%d-*-*-%.240s-*";
      sprintf(buf, fmt,
            faPtr->foundry,
            family,
            ((faPtr->weight > TK_FW_NORMAL) ? "bold" : "medium"),
            ((faPtr->slant == TK_FS_ROMAN) ? 'r' :
             (faPtr->slant == TK_FS_ITALIC) ? 'i' : 'o'),
            ((faPtr->setwidth == TK_SW_NORMAL) ? "normal" : "*"),
            pixelsize,
            dpi, dpi,
            charset);
      doExactLoad = 1;
    } else {
      char psBuf[8];
      sprintf(psBuf, "%d", pixelsize);
      fmt = "-%.200s-%.200s-%s-%c-%s-*-%s-*-%d-%d-*-*-%s-*";
      sprintf(buf, fmt,
            ((faPtr->foundry != NULL) ? faPtr->foundry : "*"),
            family,
            ((faPtr->weight > TK_FW_NORMAL) ? "bold" : "medium"),
            ((faPtr->slant == TK_FS_ROMAN) ? 'r' :
             (faPtr->slant == TK_FS_ITALIC) ? 'i' : 'o'),
            ((faPtr->setwidth == TK_SW_NORMAL) ? "normal" : "*"),
            ((pixelsize > 0) ? psBuf : "*"),
            dpi, dpi,
            charset);
    }

    /* Find the font name form hash. */
#ifdef UNIXFONT_DEBUG
    fprintf(stderr, "debugFont: search '%s'\n", buf);
#endif /* UNIXFONT_DEBUG */
    entry = Tcl_FindHashEntry(&xFindFontTable, (char *)Tk_GetUid(buf));
    if (entry != NULL) {
      char *opendName = (char *)Tcl_GetHashValue(entry);
      fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), opendName);
      if (fontStructPtr != NULL) {
          goto end;
      } else {
          /*
           * ... Maybe X font search path was changed.
           */
          Tcl_DeleteHashEntry(entry);
      }
    }
    entry = NULL;
    bufLen = strlen(buf);
    memcpy(orgTryName, buf, (unsigned int)bufLen);
    orgTryName[bufLen] = 0;
    if (doExactLoad == 1) {
      fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), buf);
    }
    if (fontStructPtr != NULL) {
      goto end;
    }

    oneMoreTry:
#else
    fmt = "-*-%.240s-*-*-*-*-*-*-*-*-*-*-*-*";
    sprintf(buf, fmt, family);
#endif /* KANJI */
    nameList = XListFonts(Tk_Display(tkwin), buf, 10000, &numNames);
    if (numNames == 0) {
#ifdef KANJI
      if (onceAgain == 0) {
          careDPI = 0;
          fmt = "-*-%.240s-*-*-*--*-*-*-*-*-*-%.240s-*";
          sprintf(buf, fmt, family, charset);
          onceAgain = 1;
          goto oneMoreTry;
      } else if (onceAgain == 1) {
          careDPI = 0;
          fmt = "-*-%.240s-*-*-*--*-*-*-*-*-*-*-*";
          sprintf(buf, fmt, family);
          onceAgain = 2;
          goto oneMoreTry;
      } else {
          careDPI = 0;
          fmt = "-*-%.240s-*-*-*--*-*-*-*-*-*-%.240s-*";
          sprintf(buf, fmt, "fixed", charset);
      }
#else
      /*
       * Try getting some system font.
       */

      sprintf(buf, fmt, "fixed");
#endif /* KANJI */
      nameList = XListFonts(Tk_Display(tkwin), buf, 10000, &numNames);
      if (numNames == 0) {
          getsystem:
#ifdef KANJI
          if (strcasecmp(charset, "jisx0208.1983") == 0) {
            fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), "k14");
            memcpy(buf, "k14", 3);
            buf[3] = 0;
          } else {
            fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), "fixed");
            memcpy(buf, "fixed", 5);
            buf[5] = 0;
          }
#else
          fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), "fixed");
#endif /* KANJI */
          if (fontStructPtr == NULL) {
            fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), "*");
#ifdef KANJI
            buf[0] = '*';
            buf[1] = 0;
#endif /* KANJI */
            if (fontStructPtr == NULL) {
                panic("TkpGetFontFromAttributes: cannot get any font");
            }
          }
          goto end;
      }
    }

    /*
     * Inspect each of the XLFDs and pick the one that most closely
     * matches the desired attributes.
     */

    bestIdx = 0;
    bestScore = INT_MAX;
    bestScaleableIdx = 0;
    bestScaleableScore = INT_MAX;

    for (i = 0; i < numNames; i++) {
      score = 0;
      scaleable = 0;
#ifdef KANJI
      memset((VOID *)&xa, 0, sizeof(TkXLFDAttributes));
      TkInitFontAttributes(&(xa.fa));
#endif /* KANJI */
      if (TkParseXLFD(nameList[i], &xa) != TCL_OK) {
          continue;
      }
#ifdef KANJI
      if (xa.fa.pointsize > 0) {
          xaPixelsize = TkpConvertPointToPixel(tkwin, xa.fa.pointsize);
      } else {
          xaPixelsize = -xa.fa.pointsize;
      }

      /*
       * OK, we use -misc-*, -jis-* as well as -adobe-*.
       */
      if (xa.charset != TK_CS_KANJI) {
          if (strcasecmp(xa.foundry, "adobe") != 0) {
            score += 3000;
          }
      }
#else
      xaPixelsize = -xa.fa.pointsize;

      /*
       * Since most people used to use -adobe-* in their XLFDs,
       * preserve the preference for "adobe" foundry.  Otherwise
       * some applications looks may change slightly if another foundry
       * is chosen.
       */

      if (strcasecmp(xa.foundry, "adobe") != 0) {
          score += 3000;
      }
#endif /* KANJI */
#ifdef KANJI
      if (faPtr->foundry != NULL) {
          if (strcasecmp(xa.foundry, faPtr->foundry) != 0) {
            score += 50000;
            /*
             * further more, if charset != TK_CS_NORMAL, make this BAD.
             */
            if (xa.charset != TK_CS_NORMAL) {
                score += 15000;
            }
          }
      }
      if (*family != '*') {
          if (strcasecmp(xa.fa.family, family) != 0) {
            score += 50000;
            /*
             * further more, if charset != TK_CS_NORMAL, make this BAD.
             */
            if (xa.charset != TK_CS_NORMAL) {
                score += 15000;
            }
          }
          if (faPtr->foundry == NULL && xa.charset == TK_CS_KANJI) {
            if (strcasecmp(family, "fixed") == 0) {
                if (strcasecmp(xa.foundry, "jis") != 0 &&
                  strcasecmp(xa.foundry, "misc") != 0) {
                  /*
                   * foundry is not specified, family is "fixed".
                   * In such a case, we preffer "jis" or "misc" foundry.
                   */
                  score += 10000;
                }
            }
          }
      }
      if (*charset == '*') {
          if (xa.charset != TK_CS_NORMAL) {
            score += 15000;
          }
      }
#if 0
      if (xa.resX != dpi) {
          score += ((careDPI == 1) ? 50000 : 25000);
      }
      if (xa.resY != dpi) {
          score += ((careDPI == 1) ? 50000 : 25000);
      }
#else
      if (xa.resX != dpi || xa.resY != dpi) {
          int dpiDiff = (xa.resX + xa.resY) / 2.0 - (int)realDPI;
          if (dpiDiff < 0) {
            dpiDiff = -dpiDiff;
          }
          score += dpiDiff * ((careDPI == 1) ? 12 : 10);
      }
#endif
#endif /* KANJI */
      if (xa.fa.pointsize == 0) {
          /*
           * A scaleable font is almost always acceptable, but the
           * corresponding bitmapped font would be better.
           */
#ifdef KANJI
          /*
           * eg.
           * -adobe-courier-medium-r-normal--0-0-75-75-m-0-iso8859-1
           * -adobe-courier-medium-r-normal--12-120-75-75-m-70-iso8859-1
           *      for pixel size 13, I preffer bitmap.
           */
          score += 150;
#else
          score += 10;
#endif /* KANJI */
          scaleable = 1;
      } else {
          /*
           * A font that is too small is better than one that is too
           * big.
           */

          if (xaPixelsize > pixelsize) {
            score += (xaPixelsize - pixelsize) * 120;
          } else { 
            score += (pixelsize - xaPixelsize) * 100;
          }
      }

      score += ABS(xa.fa.weight - faPtr->weight) * 30;
      score += ABS(xa.fa.slant - faPtr->slant) * 25;
      if (xa.slant == TK_FS_OBLIQUE) {
          /*
           * Italic fonts are preferred over oblique. */

          score += 4;
      }

      if (xa.setwidth != TK_SW_NORMAL) {
          /*
           * The normal setwidth is highly preferred.
           */
          score += 2000;
      }
      if (xa.charset == TK_CS_OTHER) {
          /*
           * The standard character set is highly preferred over
           * foreign languages charsets (because we don't support
           * other languages yet).
           */
          score += 11000;
      }
      if ((xa.charset == TK_CS_NORMAL) && (xa.encoding != 1)) {
          /*
           * The '1' encoding for the characters above 0x7f is highly
           * preferred over the other encodings.
           */
          score += 8000;
      }

      if (scaleable) {
          if (score < bestScaleableScore) {
            bestScaleableIdx = i;
            bestScaleableScore = score;
          }
      } else {
          if (score < bestScore) {
            bestIdx = i;
            bestScore = score;
          }
      }
      if (score == 0) {
          break;
      }
    }

#ifdef UNIXFONT_DEBUG
    fprintf(stderr, "debugScale: p = %d, scale %d '%s': bitmap %d '%s'\n",
          pixelsize,
          bestScaleableScore, nameList[bestScaleableIdx],
          bestScore, nameList[bestIdx]);
#endif /* UNIXFONT_DEBUG */

    /*
     * Now we know which is the closest matching scaleable font and the
     * closest matching bitmapped font.  If the scaleable font was a
     * better match, try getting the scaleable font; however, if the
     * scalable font was not actually available in the desired
     * pointsize, fall back to the closest bitmapped font.
     */

    fontStructPtr = NULL;
    if (bestScaleableScore < bestScore) {
#ifdef KANJI
      char *str;
      int len;
#else
      char *str, *rest;
#endif /* KANJI */
      
      /*
       * Fill in the desired pointsize info for this font.
       */

      tryscale:
#ifdef KANJI
      /* use XLFD field as possible as I can, means use all field
         * except the pixelsize. */
      str = nameList[bestScaleableIdx];
      for (i = 0; i < XLFD_PIXEL_SIZE; i++) {
          str = strchr(str + 1, '-');
      }
      str++;
      len = str - nameList[bestScaleableIdx];
      memcpy(buf, nameList[bestScaleableIdx], (unsigned int)len);
      sprintf(buf + len, "%d-0", pixelsize);
      len = strlen(buf);
      str = strchr(str + 1, '-'); /* pass pixel. */
      str = strchr(str + 1, '-'); /* pass point. */
      sprintf(buf + len, "%s", str);
#else
      str = nameList[bestScaleableIdx];
      for (i = 0; i < XLFD_PIXEL_SIZE - 1; i++) {
          str = strchr(str + 1, '-');
      }
      rest = str;
      for (i = XLFD_PIXEL_SIZE - 1; i < XLFD_REGISTRY; i++) {
          rest = strchr(rest + 1, '-');
      }
      *str = '\0';
      sprintf(buf, "%.240s-*-%d-*-*-*-*-*%s", nameList[bestScaleableIdx],
            pixelsize, rest);
      *str = '-';
#endif /* KANJI */
#ifdef UNIXFONT_DEBUG
      fprintf(stderr, "debugScale: open '%s' idx %d\n", buf, bestScaleableIdx + 1);
#endif /* UNIXFONT_DEBUG */
      fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), buf);
      bestScaleableScore = INT_MAX;
    }
    if (fontStructPtr == NULL) {
      strcpy(buf, nameList[bestIdx]);
      fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), buf);
      if (fontStructPtr == NULL) {
          /*
           * This shouldn't happen because the font name is one of the
           * names that X gave us to use, but it does anyhow.
           */

          if (bestScaleableScore < INT_MAX) {
            goto tryscale;
          } else {
            XFreeFontNames(nameList);
            goto getsystem;
          }
      }
    }
    XFreeFontNames(nameList);

    end:
    fontPtr = AllocFont(tkFontPtr, tkwin, fontStructPtr, buf);
    fontPtr->font.fa.underline  = faPtr->underline;
    fontPtr->font.fa.overstrike = faPtr->overstrike;
#ifdef KANJI
    fontPtr->font.fa.pointAdjust = faPtr->pointAdjust;
    if (faPtr->pointsize < 0) {
      /* user specified pixelsize ?? */
      fontPtr->font.fa.pointsize = faPtr->pointsize;
    }
    if (faPtr->foundry == NULL) {
      fontPtr->font.fa.foundry = NULL;
    }

    /* Create a hash entry for font name queryed at the top of this routine. */
    if (entry == NULL && orgTryName[0] != 0) {
#ifdef UNIXFONT_DEBUG
      fprintf(stderr, "debugFont: create '%s' -> '%s'\n", orgTryName, buf);
#endif /* UNIXFONT_DEBUG */
      entry = Tcl_CreateHashEntry(&xFindFontTable, (char *)Tk_GetUid(orgTryName), &new);
      Tcl_SetHashValue(entry, (ClientData)Tk_GetUid(buf));
    }
#endif /* KANJI */

    return (TkFont *) fontPtr;
}


/*
 *---------------------------------------------------------------------------
 *
 * TkpDeleteFont --
 *
 *    Called to release a font allocated by TkpGetNativeFont() or
 *    TkpGetFontFromAttributes().  The caller should have already
 *    released the fields of the TkFont that are used exclusively by
 *    the generic TkFont code.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    TkFont is deallocated.
 *
 *---------------------------------------------------------------------------
 */

void
TkpDeleteFont(tkFontPtr)
    TkFont *tkFontPtr;        /* Token of font to be deleted. */
{
    UnixFont *fontPtr;

    fontPtr = (UnixFont *) tkFontPtr;

#ifdef KANJI
    if (Tk_FontType(tkFontPtr) == TK_FONT_COMPOUND) {
      if (fontPtr->font.asciiFontPtr != NULL) {
          Tk_DeleteCompoundParent((Tk_Font)fontPtr->font.asciiFontPtr,
                            (Tk_Font)fontPtr);
          Tk_FreeFont((Tk_Font)fontPtr->font.asciiFontPtr);
      }
      if (fontPtr->font.kanjiFontPtr != NULL) {
          Tk_DeleteCompoundParent((Tk_Font)fontPtr->font.kanjiFontPtr,
                            (Tk_Font)fontPtr);
          Tk_FreeFont((Tk_Font)fontPtr->font.kanjiFontPtr);
      }
    } else {
      Tk_FreeCompoundParent((Tk_Font)fontPtr);
      XFreeFont(fontPtr->display, fontPtr->fontStructPtr);
      if (fontPtr->types != NULL) ckfree(fontPtr->types);
      if (fontPtr->widths != NULL) ckfree(fontPtr->widths);
    }
#ifdef UNIXFONT_DEBUG
    fontPtr->isFreed = 1;
#endif /* UNIXFONT_DEBUG */
#else
    XFreeFont(fontPtr->display, fontPtr->fontStructPtr);
#endif /* KANJI */
    ckfree((char *) fontPtr);
}

/*
 *---------------------------------------------------------------------------
 *
 * TkpGetFontFamilies --
 *
 *    Return information about the font families that are available
 *    on the display of the given window.
 *
 * Results:
 *    interp->result is modified to hold a list of all the available
 *    font families.
 *
 * Side effects:
 *    None.
 *
 *---------------------------------------------------------------------------
 */
 
void
TkpGetFontFamilies(interp, tkwin)
    Tcl_Interp *interp;
    Tk_Window tkwin;
{
    int i, new, numNames;
#ifdef KANJI
    char *family, *end;
#else
    char *family, *end, *p;
#endif /* KANJI */
    Tcl_HashTable familyTable;
    Tcl_HashEntry *hPtr;
    Tcl_HashSearch search;
    char **nameList;

    Tcl_InitHashTable(&familyTable, TCL_STRING_KEYS);

    nameList = XListFonts(Tk_Display(tkwin), "*", 10000, &numNames);
    for (i = 0; i < numNames; i++) {
      if (nameList[i][0] != '-') {
          continue;
      }
      family = strchr(nameList[i] + 1, '-');
      if (family == NULL) {
          continue;
      }
      family++;
      end = strchr(family, '-');
      if (end == NULL) {
          continue;
      }
      *end = '\0';
#ifdef KANJI
      Tcl_CreateHashEntry(&familyTable, Tk_GetUid(family), &new);
      *end = '-';
#else
      for (p = family; *p != '\0'; p++) {
          if (isupper(UCHAR(*p))) {
            *p = tolower(UCHAR(*p));
          }
      }
      Tcl_CreateHashEntry(&familyTable, family, &new);
#endif /* KANJI */
    }

    hPtr = Tcl_FirstHashEntry(&familyTable, &search);
    while (hPtr != NULL) {
      Tcl_AppendElement(interp, Tcl_GetHashKey(&familyTable, hPtr));
      hPtr = Tcl_NextHashEntry(&search);
    }

    Tcl_DeleteHashTable(&familyTable);
    XFreeFontNames(nameList);
}

/*
 *---------------------------------------------------------------------------
 *
 *  Tk_MeasureChars --
 *
 *    Determine the number of characters from the string that will fit
 *    in the given horizontal span.  The measurement is done under the
 *    assumption that Tk_DrawChars() will be used to actually display
 *    the characters.
 *
 * Results:
 *    The return value is the number of characters from source that
 *    fit into the span that extends from 0 to maxLength.  *lengthPtr is
 *    filled with the x-coordinate of the right edge of the last
 *    character that did fit.
 *
 * Side effects:
 *    None.
 *
 *---------------------------------------------------------------------------
 */
int
Tk_MeasureChars(tkfont, source, numChars, maxLength, flags, lengthPtr)
    Tk_Font tkfont;           /* Font in which characters will be drawn. */
    CONST char *source;       /* Characters to be displayed.  Need not be
                         * '\0' terminated. */
    int numChars;       /* Maximum number of characters to consider
                         * from source string. */
    int maxLength;            /* If > 0, maxLength specifies the longest
                         * permissible line length; don't consider any
                         * character that would cross this
                         * x-position.  If <= 0, then line length is
                         * unbounded and the flags argument is
                         * ignored. */
    int flags;                /* Various flag bits OR-ed together:
                         * TK_PARTIAL_OK means include the last char
                         * which only partially fit on this line.
                         * TK_WHOLE_WORDS means stop on a word
                         * boundary, if possible.
                         * TK_AT_LEAST_ONE means return at least one
                         * character even if no characters fit. */
    int *lengthPtr;           /* Filled with x-location just after the
                         * terminating character. */
{
    UnixFont *fontPtr;
    CONST char *p;            /* Current character. */
    CONST char *term;         /* Pointer to most recent character that
                         * may legally be a terminating character. */
    int termX;                /* X-position just after term. */
    int curX;                 /* X-position corresponding to p. */
    int newX;                 /* X-position corresponding to p+1. */
    int c, sawNonSpace;

    fontPtr = (UnixFont *) tkfont;
#ifdef KANJI
    if (Tk_FontType(tkfont) == TK_FONT_COMPOUND) {
      fontPtr = (UnixFont *)fontPtr->font.asciiFontPtr;
    }
#endif /* KANJI */

    if (numChars == 0) {
      *lengthPtr = 0;
      return 0;
    }

    if (maxLength <= 0) {
      maxLength = INT_MAX;
    }

    newX = curX = termX = 0;
    p = term = source;
    sawNonSpace = !isspace(UCHAR(*p));

    /*
     * Scan the input string one character at a time, calculating width.
     */

    for (c = UCHAR(*p); ; ) {
      newX += fontPtr->widths[c];
      if (newX > maxLength) {
          break;
      }
      curX = newX;
      numChars--;
      p++;
      if (numChars == 0) {
          term = p;
          termX = curX;
          break;
      }

      c = UCHAR(*p);
      if (isspace(c)) {
          if (sawNonSpace) {
            term = p;
            termX = curX;
            sawNonSpace = 0;
          }
      } else {
          sawNonSpace = 1;
      }
    }

    /*
     * P points to the first character that doesn't fit in the desired
     * span.  Use the flags to figure out what to return.
     */

    if ((flags & TK_PARTIAL_OK) && (numChars > 0) && (curX < maxLength)) {
      /*
       * Include the first character that didn't quite fit in the desired
       * span.  The width returned will include the width of that extra
       * character.
       */

      numChars--;
      curX = newX;
      p++;
    }
    if ((flags & TK_AT_LEAST_ONE) && (term == source) && (numChars > 0)) {
      term = p;
      termX = curX;
      if (term == source) {
          term++;
          termX = newX;
      }
    } else if ((numChars == 0) || !(flags & TK_WHOLE_WORDS)) {
      term = p;
      termX = curX;
    }

    *lengthPtr = termX;
    return term-source;
}

/*
 *---------------------------------------------------------------------------
 *
 * Tk_DrawChars, DrawChars --
 *
 *    Draw a string of characters on the screen.  Tk_DrawChars()
 *    expands control characters that occur in the string to \X or
 *    \xXX sequences.  DrawChars() just draws the strings.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    Information gets drawn on the screen.
 *
 *---------------------------------------------------------------------------
 */

void
Tk_DrawChars(display, drawable, gc, tkfont, source, numChars, x, y)
    Display *display;         /* Display on which to draw. */
    Drawable drawable;        /* Window or pixmap in which to draw. */
    GC gc;              /* Graphics context for drawing characters. */
    Tk_Font tkfont;           /* Font in which characters will be drawn;
                         * must be the same as font used in GC. */
    CONST char *source;       /* Characters to be displayed.  Need not be
                         * '\0' terminated.  All Tk meta-characters
                         * (tabs, control characters, and newlines)
                         * should be stripped out of the string that
                         * is passed to this function.  If they are
                         * not stripped out, they will be displayed as
                         * regular printing characters. */
    int numChars;       /* Number of characters in string. */
    int x, y;                 /* Coordinates at which to place origin of
                         * string when drawing. */
{
    UnixFont *fontPtr;
    CONST char *p;
    int i, type;
    char buf[4];

    fontPtr = (UnixFont *) tkfont;
#ifdef KANJI
    if (Tk_FontType(tkfont) == TK_FONT_COMPOUND) {
      fontPtr = (UnixFont *)fontPtr->font.asciiFontPtr;
    }
#endif /* KANJI */

    p = source;
    for (i = 0; i < numChars; i++) {
      type = fontPtr->types[UCHAR(*p)];
      if (type != NORMAL) {
          DrawChars(display, drawable, gc, fontPtr, source, p - source, x, y);
          x += XTextWidth(fontPtr->fontStructPtr, source, p - source);
          if (type == REPLACE) {
            DrawChars(display, drawable, gc, fontPtr, buf,
                  GetControlCharSubst(UCHAR(*p), buf), x, y);
            x += fontPtr->widths[UCHAR(*p)];
          }
          source = p + 1;
      }
      p++;
    }

    DrawChars(display, drawable, gc, fontPtr, source, p - source, x, y);
}

static void
DrawChars(display, drawable, gc, fontPtr, source, numChars, x, y)
    Display *display;         /* Display on which to draw. */
    Drawable drawable;        /* Window or pixmap in which to draw. */
    GC gc;              /* Graphics context for drawing characters. */
    UnixFont *fontPtr;        /* Font in which characters will be drawn;
                         * must be the same as font used in GC. */
    CONST char *source;       /* Characters to be displayed.  Need not be
                         * '\0' terminated.  All Tk meta-characters
                         * (tabs, control characters, and newlines)
                         * should be stripped out of the string that
                         * is passed to this function.  If they are
                         * not stripped out, they will be displayed as
                         * regular printing characters. */
    int numChars;       /* Number of characters in string. */
    int x, y;                 /* Coordinates at which to place origin of
                         * string when drawing. */
{
    /*
     * Perform a quick sanity check to ensure we won't overflow the X
     * coordinate space.
     */
    
    if ((x + (fontPtr->fontStructPtr->max_bounds.width * numChars) > 0x7fff)) {
      int length;

      /*
       * The string we are being asked to draw is too big and would overflow
       * the X coordinate space.  Unfortunatley X servers aren't too bright
       * and so they won't deal with this case cleanly.  We need to truncate
       * the string before sending it to X.
       */

      numChars = Tk_MeasureChars((Tk_Font) fontPtr, source, numChars,
            0x7fff - x, 0, &length);
    }

    XDrawString(display, drawable, gc, x, y, source, numChars);

    if (fontPtr->font.fa.underline != 0) {
      XFillRectangle(display, drawable, gc, x,
            y + fontPtr->underlinePos,
            (unsigned) XTextWidth(fontPtr->fontStructPtr, source, numChars),
            (unsigned) fontPtr->barHeight);
    }
    if (fontPtr->font.fa.overstrike != 0) {
      y -= fontPtr->font.fm.descent + (fontPtr->font.fm.ascent) / 10;
      XFillRectangle(display, drawable, gc, x, y,
            (unsigned) XTextWidth(fontPtr->fontStructPtr, source, numChars),
            (unsigned) fontPtr->barHeight);
    }
}
#ifdef KANJI

/*
 *---------------------------------------------------------------------------
 *
 * ComputeFontWidth
 *
 *    Compute the font width.
 *
 * Results:
 *    Width of each symbol is stored in fontPtr->widths.
 *
 * Side effects:
 *    None.
 *
 *---------------------------------------------------------------------------
 */
static void
ComputeFontWidth(fontPtr)
     UnixFont *fontPtr;
{
    XFontStruct *fontStructPtr = fontPtr->fontStructPtr;
    int i, width, firstChar, lastChar, n, replaceOK;
    char *p;
    char buf[4];
    switch (Tk_FontType(fontPtr)) {
      case TK_FONT_GENERIC: {
          fontPtr->font.asciiFontPtr = (TkFont *)fontPtr;
          fontPtr->font.kanjiFontPtr = NULL;
          fontPtr->types = (char *)ckalloc(256);
          fontPtr->widths = (unsigned char *)ckalloc(256);
          memset((VOID *)(fontPtr->types), SKIP, 256);
          memset((VOID *)(fontPtr->widths), 0, 256);

          firstChar = fontStructPtr->min_char_or_byte2;
          lastChar = fontStructPtr->max_char_or_byte2;
          for (i = 0; i < 256; i++) {
            if ((i == 0177) || (i < firstChar) || (i > lastChar)) {
                fontPtr->types[i] = REPLACE;
            } else {
                fontPtr->types[i] = NORMAL;
            }
          }

          /*
           * Compute the widths for all the normal characters.  Any other
           * characters are given an initial width of 0.  Also, this determines
           * if this is a fixed or variable width font, by comparing the widths
           * of all the normal characters.
           */
      
          width = 0;
          for (i = 0; i < 256; i++) {
            if (fontPtr->types[i] != NORMAL) {
                n = 0;
            } else if (fontStructPtr->per_char == NULL) {
                n = fontStructPtr->max_bounds.width;
            } else {
                n = fontStructPtr->per_char[i - firstChar].width;
            }
            fontPtr->widths[i] = n;
            if (n != 0) {
                if (width == 0) {
                  width = n;
                } else if (width != n) {
                  fontPtr->font.fm.fixed = 0;
                }
            }
          }
      
          /*
           * Compute the widths of the characters that should be replaced with
           * control character expansions.  If the appropriate chars are not
           * available in this font, then control character expansions will not
           * be used; control chars will be invisible & zero-width.
           */

          replaceOK = 1;
          for (p = hexChars; *p != '\0'; p++) {
            if ((UCHAR(*p) < firstChar) || (UCHAR(*p) > lastChar)) {
                replaceOK = 0;
                break;
            }
          }
          for (i = 0; i < 256; i++) {
            if (fontPtr->types[i] == REPLACE) {
                if (replaceOK) {
                  n = GetControlCharSubst(i, buf);
                  for ( ; --n >= 0; ) {
                      fontPtr->widths[i] += fontPtr->widths[UCHAR(buf[n])];
                  }
                } else {
                  fontPtr->types[i] = SKIP;
                }
            }
          }
          break;
      }

      case TK_FONT_2BYTES: {
#define TWO_BYTES_RANGE 65536
#define KANJI_RANGE     32896 /* 128*256+128 */
          int min_byte1 = fontStructPtr->min_byte1;
          int max_byte1 = fontStructPtr->max_byte1;
          int min_byte2 = fontStructPtr->min_char_or_byte2;
          int max_byte2 = fontStructPtr->max_char_or_byte2;
          int rownum = max_byte2 - min_byte2 + 1;
          int i, j, n;
          static char wrapupchars1[] = { 2, 3, 4, 5, 9, 10, 28, 55, 57, 0 };
          static char wrapupchars4[] = { 1, 3, 5, 7, 9, 35, 67, 69, 71, 78, 0 };
          static char wrapupchars5[] = { 1, 3, 5, 7, 9, 35, 67, 69, 71, 78, 85, 86, 0 };

          fontPtr->font.asciiFontPtr = NULL;
          fontPtr->font.kanjiFontPtr = (TkFont *)fontPtr;
          fontPtr->types = (char *)ckalloc(TWO_BYTES_RANGE);
          fontPtr->widths = (unsigned char *)ckalloc(TWO_BYTES_RANGE);
          memset((VOID *)(fontPtr->types), SKIP, TWO_BYTES_RANGE);
          memset((VOID *)(fontPtr->widths), 0, TWO_BYTES_RANGE);
          
          for( i = min_byte1 ; i <= max_byte1 ; i++ ) {
            for( j = min_byte2 ; j <= max_byte2 ; j++ ) {
                n = (i<<8) + j;
                n &= 0x7f7f;        /* for EUC encoding kanji font (ex DEC's) */
                if (n < 0 || n > KANJI_RANGE) continue;
                fontPtr->types[n] = NORMAL;
                if( fontStructPtr->per_char == NULL ) {
                  fontPtr->widths[n] = fontStructPtr->min_bounds.width;
                } else {
                  fontPtr->widths[n] = 
                  fontStructPtr->per_char[(i-min_byte1)*rownum+(j-min_byte2)].width;
                }
            }
          }
          for (i = 0; wrapupchars1[i] > 0; i++) {
            n = 0x2120 + wrapupchars1[i];
            if (fontPtr->types[n] == NORMAL) fontPtr->types[n] = WRAPUP;
          }
          for (i = 0; wrapupchars4[i] > 0; i++) {
            n = 0x2420 + wrapupchars4[i];
            if (fontPtr->types[n] == NORMAL) fontPtr->types[n] = WRAPUP;
          }
          for (i = 0; wrapupchars5[i] > 0; i++) {
            n = 0x2520 + wrapupchars5[i];
            if (fontPtr->types[n] == NORMAL) fontPtr->types[n] = WRAPUP;
          }
          break;
      }
    }
}

/*
 *---------------------------------------------------------------------------
 *
 * CreateFakeUnixFont
 *
 *    Create UnixFont for failsafe font.
 *
 * Results:
 *    A UnixFont that can be used only for failsafe font.
 *
 * Side effects:
 *    A UnixFont structure is allocated.
 *
 *---------------------------------------------------------------------------
 */
static char *defaultFontName = NULL;
static Tcl_HashTable *defaultFontTab = NULL;

static UnixFont *
CreateFakeUnixFont(dpy, name)
     Display *dpy;
     char *name;
{
    unsigned long value;
    UnixFont *ret = (UnixFont *)ckalloc(sizeof(UnixFont));
    
    memset((VOID *)ret, 0, sizeof(UnixFont));

    ret->display = dpy;
    ret->fontStructPtr = XLoadQueryFont(dpy, name);
    if (ret->fontStructPtr == NULL) {
      ckfree(ret);
      return NULL;
    }
    ret->font.fid = ret->fontStructPtr->fid;

    if (ret->fontStructPtr->min_byte1 == 0 && ret->fontStructPtr->max_byte1 == 0) {
      Tk_FontType(ret) = TK_FONT_GENERIC;
      Tk_FontCharset(ret) = Tk_GetUid("iso8859");
    } else {
      Tk_FontType(ret) = TK_FONT_2BYTES;
      Tk_FontCharset(ret) = Tk_GetUid("jisx0208.1983");
    }
    ComputeFontWidth(ret);

    if (XGetFontProperty(ret->fontStructPtr, XA_UNDERLINE_POSITION, &value)) {
      ret->underlinePos = value;
    } else {
      ret->underlinePos = ret->fontStructPtr->descent / 2;
    }
    ret->barHeight = 0;
    if (XGetFontProperty(ret->fontStructPtr, XA_UNDERLINE_THICKNESS, &value)) {
      ret->barHeight = value;
    }
    if (ret->barHeight == 0) {
      ret->barHeight = ret->widths['I'] / 3;
      if (ret->barHeight == 0) {
          ret->barHeight = 1;
      }
    }
    if (ret->underlinePos + ret->barHeight > ret->fontStructPtr->descent) {
      ret->barHeight = ret->fontStructPtr->descent - ret->underlinePos;
      if (ret->barHeight == 0) {
          ret->underlinePos--;
          ret->barHeight = 1;
      }
    }
    ret->font.underlinePos = ret->underlinePos;
    ret->font.underlineHeight = ret->barHeight;

    return ret;
}

/*
 *---------------------------------------------------------------------------
 *
 * DeleteFakeUnixFont
 *
 *    Delete UnixFont for failsafe font.
 *
 * Results:
 *    A UnixFont created by CreateFakeUnixFont() is deleted.
 *
 * Side effects:
 *    A UnixFont structure is freed.
 *
 *---------------------------------------------------------------------------
 */
static void
DeleteFakeUnixFont(fontPtr)
     UnixFont *fontPtr;
{
    XFreeFont(fontPtr->display, fontPtr->fontStructPtr);
    ckfree(fontPtr->types);
    ckfree(fontPtr->widths);
#ifdef UNIXFONT_DEBUG
    fontPtr->isFreed = 1;
#endif /* UNIXFONT_DEBUG */
    ckfree((char *)fontPtr);
}

/*
 *---------------------------------------------------------------------------
 *
 * TkpGetDefaultFontByDisplay
 *
 *    Get the failsafe font.
 *
 * Results:
 *    A UnixFont created by CreateFakeUnixFont() is returned.
 *
 * Side effects:
 *    None.
 *
 *---------------------------------------------------------------------------
 */
Tk_Font
TkpGetDefaultFontByDisplay(dpy)
     Display *dpy;
{
    Tcl_HashEntry *ent = Tcl_FindHashEntry(defaultFontTab, (char *)dpy);
    if (ent != NULL) {
      return (Tk_Font)Tcl_GetHashValue(ent);
    }
    return NULL;
}

/*
 *---------------------------------------------------------------------------
 *
 * UpdateDefaultFont
 *
 *    Set the failsafe font.
 *
 * Results:
 *    A UnixFont created by CreateFakeUnixFont() is stored.
 *
 * Side effects:
 *      If old value exists, it will be freed.
 *
 *---------------------------------------------------------------------------
 */
static void
UpdateDefaultFont(fontPtr, dpy)
     UnixFont *fontPtr;
     Display *dpy;
{
    int new;
    Tcl_HashEntry *ent;
    UnixFont *old = (UnixFont *)TkpGetDefaultFontByDisplay(dpy);

    if (old != NULL) {
      DeleteFakeUnixFont(old);
    }
    ent = Tcl_CreateHashEntry(defaultFontTab, (char *)dpy, &new);
    Tcl_SetHashValue(ent, (ClientData)fontPtr);
}

/*
 *---------------------------------------------------------------------------
 *
 * TkpDefaultFontPkgInit
 *
 *    Initialize default font environment.
 *
 * Results:
 *    failsafe font environment is initialized.
 *
 * Side effects:
 *      None.
 *
 *---------------------------------------------------------------------------
 */
void
TkpDefaultFontPkgInit()
{
    if (defaultFontTab == NULL) {
      defaultFontTab = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
      Tcl_InitHashTable(defaultFontTab, TCL_ONE_WORD_KEYS);
    }
}

/*
 *---------------------------------------------------------------------------
 *
 * TkpDefaultFontPkgFree
 *
 *    Free default font environment.
 *
 * Results:
 *    failsafe font environment is freed.
 *
 * Side effects:
 *      None.
 *
 *---------------------------------------------------------------------------
 */
void
TkpDefaultFontPkgFree()
{
    Tcl_HashEntry *ent;
    Tcl_HashSearch search;
    UnixFont *font;

    ent = Tcl_FirstHashEntry(defaultFontTab, &search);
    while (ent != NULL) {
      font = (UnixFont *)Tcl_GetHashValue(ent);
      DeleteFakeUnixFont(font);
      ent = Tcl_NextHashEntry(&search);
    }
    Tcl_DeleteHashTable(defaultFontTab);
    ckfree((char *)defaultFontTab);
    defaultFontTab = NULL;
    if (defaultFontName != NULL) {
      ckfree(defaultFontName);
      defaultFontName = NULL;
    }
}

/*
 *---------------------------------------------------------------------------
 *
 *  TkpSetDefaultFont
 *
 *    Set the default font.
 *
 * Results:
 *    Default font name is set to static area.
 *
 * Side effects:
 *    None.
 *
 *---------------------------------------------------------------------------
 */
int
TkpSetDefaultFont(interp, tkwin, name)
     Tcl_Interp *interp;
     Tk_Window tkwin;
     char *name;
{
    int len = strlen(name);
    UnixFont *font;
    Display *dpy = Tk_Display(tkwin);

    if (name == NULL || name[0] == 0) {
      TkpDefaultFontPkgFree();
      TkpDefaultFontPkgInit();
      return TCL_OK;
    }

    font = CreateFakeUnixFont(dpy, name);
    if (font == NULL) {
      Tcl_ResetResult(interp);
      Tcl_AppendResult(interp, "can't load font \"", name, "\".", NULL);
      return TCL_ERROR;
    }

    if (defaultFontName != NULL) {
      ckfree(defaultFontName);
    }
    defaultFontName = (char *)ckalloc((len + 1) * sizeof(char));
    if (defaultFontName == NULL) {
      DeleteFakeUnixFont(font);
      return TCL_ERROR;
    }
    memcpy((VOID *)(defaultFontName), (VOID *)name, (unsigned int)len);
    defaultFontName[len] = 0;
    
    UpdateDefaultFont(font, dpy);
    return TCL_OK;
}

/*
 *---------------------------------------------------------------------------
 *
 *  TkpGetDefaultFont
 *
 *    Get the default font.
 *
 * Results:
 *    Return the default font name set by TkpSetDefaultFont().
 *
 * Side effects:
 *    None.
 *
 *---------------------------------------------------------------------------
 */
char *
TkpGetDefaultFont()
{
    if (defaultFontName == NULL) {
      return "";
    } else {
      return defaultFontName;
    }
}

/*
 *---------------------------------------------------------------------------
 *
 *  TkpGetFailsafeFont
 *
 *    Get the failsafe font.
 *
 * Results:
 *    Return the failsafe font.
 *
 * Side effects:
 *    None.
 *
 *---------------------------------------------------------------------------
 */
static void
TkpGetFailsafeFont(tkfont, asciiFPtr, kanjiFPtr)
     Tk_Font tkfont;
     UnixFont **asciiFPtr;
     UnixFont **kanjiFPtr;
{
    UnixFont *defaultF = NULL;
    int tkFontType = Tk_FontType(tkfont);
    
    if (tkFontType == TK_FONT_COMPOUND) {
      /* Sounds Goooood. */
      *asciiFPtr = (UnixFont *)(((TkFont *)tkfont)->asciiFontPtr);
      *kanjiFPtr = (UnixFont *)(((TkFont *)tkfont)->kanjiFontPtr);
      return;
    }

    {
      Display *dpy = ((UnixFont *)tkfont)->display;
      defaultF = (UnixFont *)TkpGetDefaultFontByDisplay(dpy);
      if (defaultF == NULL) {
          if (defaultFontName != NULL && defaultFontName[0] != 0) {
            defaultF = CreateFakeUnixFont(dpy, defaultFontName);
            if (defaultF != NULL) {
                UpdateDefaultFont(defaultF, dpy);
            }
          }
      }
    }

    *asciiFPtr = NULL;
    *kanjiFPtr = NULL;
    if (defaultF != NULL) {
      int defFontType = Tk_FontType((Tk_Font)defaultF);
      switch(tkFontType) {
          case TK_FONT_GENERIC: {
            *asciiFPtr = (UnixFont *)(((TkFont *)tkfont)->asciiFontPtr);
            if (defFontType == TK_FONT_COMPOUND || defFontType == TK_FONT_2BYTES) {
                /* Well, try to use kanji font in default font. */
                *kanjiFPtr = (UnixFont *)(((TkFont *)defaultF)->kanjiFontPtr);
            }
            break;
          }
          case TK_FONT_2BYTES: {
            *kanjiFPtr = (UnixFont *)(((TkFont *)tkfont)->kanjiFontPtr);
            if (defFontType == TK_FONT_COMPOUND || defFontType == TK_FONT_GENERIC) {
                *asciiFPtr = (UnixFont *)(((TkFont *)defaultF)->asciiFontPtr);
            }
            break;
          }
      }
    } else {
      switch(tkFontType) {
          case TK_FONT_GENERIC: {
            *asciiFPtr = (UnixFont *)(((TkFont *)tkfont)->asciiFontPtr);
            break;
          }
          case TK_FONT_2BYTES: {
            *kanjiFPtr = (UnixFont *)(((TkFont *)tkfont)->kanjiFontPtr);
            break;
          }
      }
    }
    if (*asciiFPtr == NULL && *kanjiFPtr == NULL) {
        panic("FailsafeFont: can't get ANY font.");
    }
    return;
}

#ifdef UNIXFONT_DEBUG
#define FailsafeFont(TK, ASC, KNJ) \
if (((UnixFont *)(TK))->isFreed == 1) { \
      panic("FailsafeFont: freed font reference."); \
} \
if (Tk_FontType(((Tk_Font)(TK))) == TK_FONT_COMPOUND) { \
      ASC = (UnixFont *)(((TkFont *)(TK))->asciiFontPtr); \
      KNJ = (UnixFont *)(((TkFont *)(TK))->kanjiFontPtr); \
      fprintf(stderr, "debugFailF: tkfont(compd) 0x%08x, ascii 0x%08x kanji 0x%08x\n", \
            (TK), (ASC), (KNJ)); \
} else { \
      TkpGetFailsafeFont(((Tk_Font)(TK)), (&(ASC)), (&(KNJ))); \
      fprintf(stderr, "debugFailF: tkfont(%s) 0x%08x, ascii 0x%08x kanji 0x%08x\n", \
            (Tk_FontType(((Tk_Font)(TK))) == TK_FONT_GENERIC) ? "ascii" : "kanji", \
            (TK), (ASC), (KNJ)); \
} \
fprintf(stderr, "\t\t'%s', '%s'\n", \
      ((ASC) != NULL) ? ((Tk_FontCharset((Tk_Font)(ASC)) != NULL) ? Tk_FontCharset((Tk_Font)(ASC)) : "") : "", \
      ((KNJ) != NULL) ? ((Tk_FontCharset((Tk_Font)(KNJ)) != NULL) ? Tk_FontCharset((Tk_Font)(KNJ)) : "") : "");
#else
#define FailsafeFont(TK, ASC, KNJ) \
if (Tk_FontType(((Tk_Font)(TK))) == TK_FONT_COMPOUND) { \
      ASC = (UnixFont *)(((TkFont *)(TK))->asciiFontPtr); \
      KNJ = (UnixFont *)(((TkFont *)(TK))->kanjiFontPtr); \
} else { \
      TkpGetFailsafeFont(((Tk_Font)(TK)), (&(ASC)), (&(KNJ))); \
}
#endif /* UNIXFONT_DEBUG */


/*
 *---------------------------------------------------------------------------
 *
 *  Tk_MeasureWChars --
 *
 *    Determine the number of characters from the string that will fit
 *    in the given horizontal span.  The measurement is done under the
 *    assumption that Tk_DrawWChars() will be used to actually display
 *    the characters.
 *
 * Results:
 *    The return value is the number of characters from source that
 *    fit into the span that extends from 0 to maxLength.  *lengthPtr is
 *    filled with the x-coordinate of the right edge of the last
 *    character that did fit.
 *
 * Side effects:
 *    None.
 *
 *---------------------------------------------------------------------------
 */
int
Tk_MeasureWChars(tkfont, source, numChars, maxLength, flags, lengthPtr)
     Tk_Font tkfont;          /* Font in which characters will be drawn. */
     CONST wchar *source;     /* Characters to be displayed.  Need not be
                         * '\0' terminated. */
     int numChars;            /* Maximum number of characters to consider
                         * from source string. */
     int maxLength;           /* If > 0, maxLength specifies the longest
                         * permissible line length; don't consider any
                         * character that would cross this
                         * x-position.  If <= 0, then line length is
                         * unbounded and the flags argument is
                         * ignored. */
     int flags;               /* Various flag bits OR-ed together:
                         * TK_PARTIAL_OK means include the last char
                         * which only partially fit on this line.
                         * TK_WHOLE_WORDS means stop on a word
                         * boundary, if possible.
                         * TK_AT_LEAST_ONE means return at least one
                         * character even if no characters fit. */
     int *lengthPtr;          /* Filled with x-location just after the
                         * terminating character. */
{
    UnixFont *kanjiF = NULL;
    UnixFont *asciiF = NULL;
    CONST wchar *p;           /* Current character. */
    CONST wchar *term;        /* Pointer to most recent character that
                         * may legally be a terminating character. */
    int termX;                /* X-position just after term. */
    int curX;                 /* X-position corresponding to p. */
    int newX;                 /* X-position corresponding to p+1. */
    int c, sawNonSpace;
  
    if (numChars == 0) {
      *lengthPtr = 0;
      return 0;
    }

    if (maxLength <= 0) {
      maxLength = INT_MAX;
    }

    newX = curX = termX = 0;
    p = term = source;
    c = UCHAR(*p);
    sawNonSpace = !ISWSPACE(c);

    FailsafeFont(tkfont, asciiF, kanjiF);

    /*
     * Scan the input string one character at a time, calculating width.
     */

    for (;;) {
      c = *p & 0x8080;
      switch(c) {
          case G0MASK:
          case G2MASK:
          case G3MASK: {
            if (asciiF != NULL) {
                c = *p & 0xff;
                newX += asciiF->widths[c];
            } else if (kanjiF != NULL) {
                c = *p & 0x7f7f;
                newX += kanjiF->widths[c];
            }
            break;
          }
          case G1MASK: {
            if (kanjiF != NULL) {
                c = *p & 0x7f7f;
                newX += kanjiF->widths[c];
            } else if (asciiF != NULL) {
                c = *p & 0xff;
                newX += asciiF->widths[c];
            }
            break;
          }
      }

      if (newX > maxLength) {
          break;
      }
      curX = newX;
      numChars--;
      p++;
      
      if (numChars == 0) {
          term = p;
          termX = curX;
          break;
      }
      
      c = UCHAR(*p);
      if (ISWSPACE(c)) {
          if (sawNonSpace) {
            term = p;
            termX = curX;
            sawNonSpace = 0;
          }
      } else {
          sawNonSpace = 1;
      }
    }

    /*
     * P points to the first character that doesn't fit in the desired
     * span.  Use the flags to figure out what to return.
     */
  
    if ((flags & TK_PARTIAL_OK) && (numChars > 0) && (curX < maxLength)) {
      /*
       * Include the first character that didn't quite fit in the desired
       * span.  The width returned will include the width of that extra
       * character.
       */
    
      numChars--;
      curX = newX;
      p++;
    }
    if ((flags & TK_AT_LEAST_ONE) && (term == source) && (numChars > 0)) {
      term = p;
      termX = curX;
      if (term == source) {
          term++;
          termX = newX;
      }
    } else if ((numChars == 0) || !(flags & TK_WHOLE_WORDS)) {
      term = p;
      termX = curX;
    }

    *lengthPtr = termX;
    return term - source;
}

/*
 *---------------------------------------------------------------------------
 *
 * Tk_DrawWChars, DrawWChars --
 *
 *    Draw a string of characters on the screen.  Tk_DrawWChars()
 *    expands control characters that occur in the string to \X or
 *    \xXX sequences.  DrawWChars() just draws the strings.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    Information gets drawn on the screen.
 *
 *---------------------------------------------------------------------------
 */

void
Tk_DrawWChars(display, drawable, gc, tkfont, source, numChars, x, y)
     Display *display;        /* Display on which to draw. */
     Drawable drawable;       /* Window or pixmap in which to draw. */
     GC gc;             /* Graphics context for drawing characters. */
     Tk_Font tkfont;          /* Font in which characters will be drawn;
                         * must be the same as font used in GC. */
     CONST wchar *source;     /* Characters to be displayed.  Need not be
                         * '\0' terminated.  All Tk meta-characters
                         * (tabs, control characters, and newlines)
                         * should be stripped out of the string that
                         * is passed to this function.  If they are
                         * not stripped out, they will be displayed as
                         * regular printing characters. */
     int numChars;            /* Number of characters in string. */
     int x, y;                /* Coordinates at which to place origin of
                         * string when drawing. */
{
    DrawWChars(display, drawable, gc, (UnixFont *)tkfont, source, numChars, x, y);
}

static int
WStrToTextItem(wstr, numWchar, fontPtr, items, numItems,
             chars, numChars, pXWidthPtr, numItemsPtr)
     wchar *wstr;
     int numWchar;
     UnixFont *fontPtr;
     XTextItem16 *items;
     int numItems;
     XChar2b *chars;
     int numChars;
     unsigned int *pXWidthPtr;
     int *numItemsPtr;
{
    int i = 0;
    int c;
    UnixFont *kanjiF = NULL;
    UnixFont *asciiF = NULL;
    int curX = 0;
    int b;
    XTextItem16 *iPtr = items;
    XChar2b *cPtr = chars;

    FailsafeFont(fontPtr, asciiF, kanjiF);

    if (asciiF != NULL && kanjiF != NULL) {
      UnixFont *lastFont = NULL;
      for (i = 0; i < numWchar; i++) {
          if ( (iPtr - items) >= numItems ) goto done;
          if ( (cPtr - chars) >= numChars ) goto done;
          c = wstr[i] & 0x8080;
          switch(c) {
            case G0MASK:
            case G2MASK:
            case G3MASK: {
                if (lastFont == kanjiF || lastFont == NULL) {
                  if (lastFont != NULL) {
                      iPtr++;
                  }
                  iPtr->delta = 0;
                  iPtr->nchars = 0;
                  iPtr->chars = cPtr;
                  lastFont = asciiF;
                  iPtr->font = lastFont->font.fid;
                }
#if 0
                if (strcasecmp(Tk_FontCharset(lastFont), "jisx0208.1983") == 0) {
                    panic("WStrToTextItem: using kanji font with ascii string.");
                }
#endif
                b = wstr[i] & 0xff;
                if (lastFont->types[b] == REPLACE) {
                  char buf[4];
                  int j;
                  int save = iPtr->nchars;
                  int numBuf = GetControlCharSubst(b, buf);
                  for (j = 0; j < numBuf; j++) {
                      if ( (cPtr - chars) >= numChars ) {
                        iPtr->nchars = save;
                        goto done;
                      }
                      cPtr->byte1 = 0;
                      cPtr->byte2 = buf[j];
                      cPtr++;
                      iPtr->nchars++;
                  }
                } else {
                  cPtr->byte1 = 0;
                  cPtr->byte2 = b;
                  cPtr++;
                  iPtr->nchars++;
                }
                curX += lastFont->widths[b];
                break;
            }

            case G1MASK: {
                if (lastFont == asciiF || lastFont == NULL) {
                  if (lastFont != NULL) {
                      iPtr++;
                  }
                  iPtr->delta = 0;
                  iPtr->nchars = 0;
                  iPtr->chars = cPtr;
                  lastFont = kanjiF;
                  iPtr->font = lastFont->font.fid;
                }
#if 0
                if (strcasecmp(Tk_FontCharset(lastFont), "jisx0208.1983") != 0) {
                    panic("WStrToTextItem: using ascii font with kanji string.");
                }
#endif
                b = wstr[i] & 0x7f7f;
                cPtr->byte1 = b >> 8;
                cPtr->byte2 = b & 0x7f;
                cPtr++;
                iPtr->nchars++;
                curX += lastFont->widths[b];
                break;
            }
          }
      }
    } else if (asciiF != NULL && kanjiF == NULL) {
      iPtr->chars = cPtr;
      iPtr->delta = 0;
      iPtr->nchars = 0;
      iPtr->font = asciiF->font.fid;
      for (i = 0; i < numWchar; i++) {
          if ( (cPtr - chars) >= numChars ) goto done;
          b = wstr[i] & 0xff;
          if (asciiF->types[b] == REPLACE) {
            char buf[4];
            int j;
            int save = iPtr->nchars;
            int numBuf = GetControlCharSubst(b, buf);
            for (j = 0; j < numBuf; j++) {
                if ( (cPtr - chars) >= numChars ) {
                  iPtr->nchars = save;
                  goto done;
                }
                cPtr->byte1 = 0;
                cPtr->byte2 = buf[j];
                cPtr++;
                iPtr->nchars++;
            }
          } else {
            cPtr->byte1 = 0;
            cPtr->byte2 = b;
            cPtr++;
            iPtr->nchars++;
          }
          curX += asciiF->widths[b];
      }
    } else if (asciiF == NULL && kanjiF != NULL) {
      iPtr->chars = cPtr;
      iPtr->delta = 0;
      iPtr->nchars = 0;
      iPtr->font = kanjiF->font.fid;
      for (i = 0; i < numWchar; i++) {
          if ( (cPtr - chars) >= numChars ) goto done;
          b = wstr[i] & 0x7f7f;
          cPtr->byte1 = b >> 8;
          cPtr->byte2 = b & 0x7f;
          cPtr++;
          iPtr->nchars++;
          curX += kanjiF->widths[b];
      }
    } else {
      panic("WStrToTextItem: No valid font!");
    }
    
    done:
    *pXWidthPtr = curX;
    *numItemsPtr = iPtr - items + 1;
    if (*numItemsPtr > numItems) *numItemsPtr = numItems;
    return i;
}


static int
DrawWChars(display, drawable, gc, fontPtr, source, numChars, x, y)
    Display *display;         /* Display on which to draw. */
    Drawable drawable;        /* Window or pixmap in which to draw. */
    GC gc;              /* Graphics context for drawing characters. */
    UnixFont *fontPtr;        /* Font in which characters will be drawn;
                         * must be the same as font used in GC. */
    CONST wchar *source;      /* Characters to be displayed.  Need not be
                         * '\0' terminated.  All Tk meta-characters
                         * (tabs, control characters, and newlines)
                         * should be stripped out of the string that
                         * is passed to this function.  If they are
                         * not stripped out, they will be displayed as
                         * regular printing characters. */
    int numChars;       /* Number of characters in string. */
    int x, y;                 /* Coordinates at which to place origin of
                         * string when drawing. */
{           
    int nItem;
    int xPos;
    int nAdv;
    int curX = x;

#define MAX_ITEMS 256
#define MAX_CHARS 1024
    XTextItem16 items[MAX_ITEMS];
    XChar2b chars[MAX_CHARS];

    while (numChars > 0) {
      nAdv = WStrToTextItem(source, numChars, fontPtr, items, MAX_ITEMS, 
                        chars, MAX_CHARS, &xPos, &nItem);

      if (nItem > 0) {
          XDrawText16(display, drawable, gc, curX, y, items, nItem);
      } else {
          break;
      }
      source += nAdv;
      curX += xPos;
      numChars -= nAdv;
#ifdef UNIXFONT_DEBUG
      fprintf(stderr, "CharDebug: source 0x%x, incr = %d, remain = %d, item = %d\n",
            source, nAdv, numChars, nItem);
#endif /* UNIXFONT_DEBUG */
    }
    xPos = curX - x;

    if (fontPtr->font.fa.underline != 0) {
      XFillRectangle(display, drawable, gc, x, y + fontPtr->underlinePos,
                   (unsigned) xPos,
                   (unsigned) fontPtr->barHeight);
    }
    if (fontPtr->font.fa.overstrike != 0) {
      y -= fontPtr->font.fm.descent + (fontPtr->font.fm.ascent) / 10;
      XFillRectangle(display, drawable, gc, x, y,
                   (unsigned) xPos,
                   (unsigned) fontPtr->barHeight);
    }
    return 0;
}
#endif /* KANJI */

/*
 *---------------------------------------------------------------------------
 *
 * AllocFont --
 *
 *    Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().
 *    Allocates and intializes the memory for a new TkFont that
 *    wraps the platform-specific data.
 *
 * Results:
 *    Returns pointer to newly constructed TkFont.  
 *
 *    The caller is responsible for initializing the fields of the
 *    TkFont that are used exclusively by the generic TkFont code, and
 *    for releasing those fields before calling TkpDeleteFont().
 *
 * Side effects:
 *    Memory allocated.
 *
 *---------------------------------------------------------------------------
 */ 

static UnixFont *
AllocFont(tkFontPtr, tkwin, fontStructPtr, fontName)
    TkFont *tkFontPtr;        /* If non-NULL, store the information in
                         * this existing TkFont structure, rather than
                         * allocating a new structure to hold the
                         * font; the existing contents of the font
                         * will be released.  If NULL, a new TkFont
                         * structure is allocated. */
    Tk_Window tkwin;          /* For display where font will be used. */
    XFontStruct *fontStructPtr;     /* X information about font. */
    CONST char *fontName;     /* The string passed to XLoadQueryFont() to
                         * construct the fontStructPtr. */
{
    UnixFont *fontPtr;
    unsigned long value;
#ifdef KANJI
    int isFirstAlloc = 0;
    char *name;
#else
    int i, width, firstChar, lastChar, n, replaceOK;
    char *name, *p;
    char buf[4];
#endif /* KANJI */
    TkXLFDAttributes xa;
#ifndef KANJI
    double d;
#endif /* !KANJI */    

    if (tkFontPtr != NULL) {
      fontPtr = (UnixFont *) tkFontPtr;
#ifdef KANJI
#ifdef UNIXFONT_DEBUG
      if (fontPtr->isFreed == 1) {
          panic("AllocFont: freed font reference.");
      }
#endif /* UNIXFONT_DEBUG */
      if (Tk_FontType(tkFontPtr) == TK_FONT_COMPOUND) {
          return (UnixFont *) tkFontPtr;
      }
      Tk_FreeCompoundParent((Tk_Font)fontPtr);
      if (fontPtr->types != NULL) {
          ckfree(fontPtr->types);
          fontPtr->types = NULL;
      }
      if (fontPtr->widths != NULL) {
          ckfree(fontPtr->widths);
          fontPtr->widths = NULL;
      }
#ifdef UNIXFONT_DEBUG
      fprintf(stderr, "debugAllocFont: tkfont(%s) 0x%08lx is re-initialized.\n",
            (Tk_FontType(tkFontPtr) == TK_FONT_GENERIC) ? "ascii" : "kanji",
            fontPtr);
#endif /* UNIXFONT_DEBUG */
#endif /* KANJI */
      XFreeFont(fontPtr->display, fontPtr->fontStructPtr);
    } else {
        fontPtr = (UnixFont *) ckalloc(sizeof(UnixFont));
#ifdef KANJI
      memset((VOID *)fontPtr, 0, sizeof(UnixFont));
      isFirstAlloc = 1;
#endif /* KANJI */
    }

    /*
     * Encapsulate the generic stuff in the TkFont. 
     */

    fontPtr->font.fid         = fontStructPtr->fid;

    if (XGetFontProperty(fontStructPtr, XA_FONT, &value) && (value != 0)) {
      name = Tk_GetAtomName(tkwin, (Atom) value);
      TkInitFontAttributes(&xa.fa);
      if (TkParseXLFD(name, &xa) == TCL_OK) {
          goto ok;
      }
    }
    TkInitFontAttributes(&xa.fa);
    if (TkParseXLFD(fontName, &xa) != TCL_OK) {
      TkInitFontAttributes(&fontPtr->font.fa);
      fontPtr->font.fa.family = Tk_GetUid(fontName);
    } else {
      ok:
#ifdef KANJI
      if (isFirstAlloc == 1) {
          memcpy((VOID *)&(fontPtr->font.fa), (VOID *)&(xa.fa),
               sizeof(TkFontAttributes));
      } else {
          /* Mayhaps we have configured value. */
          int overstrike = fontPtr->font.fa.overstrike;
          int underline = fontPtr->font.fa.underline;
          double pointAdjust = fontPtr->font.fa.pointAdjust;
          memcpy((VOID *)&(fontPtr->font.fa), (VOID *)&(xa.fa),
               sizeof(TkFontAttributes));
          fontPtr->font.fa.overstrike = overstrike;
          fontPtr->font.fa.underline = underline;
          fontPtr->font.fa.pointAdjust = pointAdjust;
      }
#else
      fontPtr->font.fa = xa.fa;
#endif /* KANJI */
    }

#ifdef KANJI
    /* If the Tk_FontType(fontPtr) == TK_FONT_OTHER, must need to
     * check whether the font is for 2 byte charset or not. To check
     * this, In X window, use the informations in XFontStruct. */
#ifdef UNIXFONT_DEBUG
    fprintf(stderr, "\nmin_char_or_byte2 = %d\n", fontStructPtr->min_char_or_byte2);
    fprintf(stderr, "max_char_or_byte2 = %d\n", fontStructPtr->max_char_or_byte2);
    fprintf(stderr, "min_byte1 = %d\n", fontStructPtr->min_byte1);
    fprintf(stderr, "max_byte1 = %d\n", fontStructPtr->max_byte1);
#endif /* UNIXFONT_DEBUG */
    if (Tk_FontType(fontPtr) != TK_FONT_GENERIC &&
      Tk_FontType(fontPtr) != TK_FONT_2BYTES &&
      Tk_FontType(fontPtr) != TK_FONT_COMPOUND) {
      if (fontStructPtr->min_byte1 == 0 && fontStructPtr->max_byte1 == 0) {
          Tk_FontType(fontPtr) = TK_FONT_GENERIC;
      } else {
          Tk_FontType(fontPtr) = TK_FONT_2BYTES;
      }
    }
#endif /* KANJI */

#ifdef KANJI 
#if 0
    if (fontPtr->font.fa.pointsize < 0) {
      fontPtr->font.fa.pointsize = TkpConvertPixelToPoint(tkwin, -(fontPtr->font.fa.pointsize));
    }
#endif
#else
    if (fontPtr->font.fa.pointsize < 0) {
      d = -fontPtr->font.fa.pointsize * 72 / 25.4;
      d *= WidthMMOfScreen(Tk_Screen(tkwin));
      d /= WidthOfScreen(Tk_Screen(tkwin));
      d += 0.5;
      fontPtr->font.fa.pointsize = (int) d;
    }
#endif /* KANJI */

    fontPtr->font.fm.ascent   = fontStructPtr->ascent;
    fontPtr->font.fm.descent  = fontStructPtr->descent;
    fontPtr->font.fm.maxWidth = fontStructPtr->max_bounds.width;
    fontPtr->font.fm.fixed    = 1;
    fontPtr->display          = Tk_Display(tkwin);
    fontPtr->fontStructPtr    = fontStructPtr;
#ifdef KANJI
    ComputeFontWidth(fontPtr);
#else

    /*
     * Classify the characters.
     */

    firstChar = fontStructPtr->min_char_or_byte2;
    lastChar = fontStructPtr->max_char_or_byte2;
    for (i = 0; i < 256; i++) {
      if ((i == 0177) || (i < firstChar) || (i > lastChar)) {
          fontPtr->types[i] = REPLACE;
      } else {
          fontPtr->types[i] = NORMAL;
      }
    }

    /*
     * Compute the widths for all the normal characters.  Any other
     * characters are given an initial width of 0.  Also, this determines
     * if this is a fixed or variable width font, by comparing the widths
     * of all the normal characters.
     */

    width = 0;
    for (i = 0; i < 256; i++) {
      if (fontPtr->types[i] != NORMAL) {
          n = 0;
      } else if (fontStructPtr->per_char == NULL) {
          n = fontStructPtr->max_bounds.width;
      } else {
          n = fontStructPtr->per_char[i - firstChar].width;
      }
      fontPtr->widths[i] = n;
      if (n != 0) {
          if (width == 0) {
            width = n;
          } else if (width != n) {
            fontPtr->font.fm.fixed = 0;
          }
      }
    }

    /*
     * Compute the widths of the characters that should be replaced with
     * control character expansions.  If the appropriate chars are not
     * available in this font, then control character expansions will not
     * be used; control chars will be invisible & zero-width.
     */

    replaceOK = 1;
    for (p = hexChars; *p != '\0'; p++) {
      if ((UCHAR(*p) < firstChar) || (UCHAR(*p) > lastChar)) {
          replaceOK = 0;
          break;
      }
    }
    for (i = 0; i < 256; i++) {
      if (fontPtr->types[i] == REPLACE) {
          if (replaceOK) {
            n = GetControlCharSubst(i, buf);
            for ( ; --n >= 0; ) {
                fontPtr->widths[i] += fontPtr->widths[UCHAR(buf[n])];
            }
          } else {
            fontPtr->types[i] = SKIP;
          }
      }
    }
#endif /* KANJI */

    if (XGetFontProperty(fontStructPtr, XA_UNDERLINE_POSITION, &value)) {
      fontPtr->underlinePos = value;
    } else {
      /*
       * If the XA_UNDERLINE_POSITION property does not exist, the X
       * manual recommends using the following value:
       */

      fontPtr->underlinePos = fontStructPtr->descent / 2;
    }
    fontPtr->barHeight = 0;
    if (XGetFontProperty(fontStructPtr, XA_UNDERLINE_THICKNESS, &value)) {
      /*
       * Sometimes this is 0 even though it shouldn't be.
       */
      fontPtr->barHeight = value;
    }
    if (fontPtr->barHeight == 0) {
      /*
       * If the XA_UNDERLINE_THICKNESS property does not exist, the X
       * manual recommends using the width of the stem on a capital
       * letter.  I don't know of a way to get the stem width of a letter,
       * so guess and use 1/3 the width of a capital I.
       */

      fontPtr->barHeight = fontPtr->widths['I'] / 3;
      if (fontPtr->barHeight == 0) {
          fontPtr->barHeight = 1;
      }
    }
    if (fontPtr->underlinePos + fontPtr->barHeight > fontStructPtr->descent) {
      /*
       * If this set of cobbled together values would cause the bottom of
       * the underline bar to stick below the descent of the font, jack
       * the underline up a bit higher.
       */

      fontPtr->barHeight = fontStructPtr->descent - fontPtr->underlinePos;
      if (fontPtr->barHeight == 0) {
          fontPtr->underlinePos--;
          fontPtr->barHeight = 1;
      }
    }
#ifdef KANJI
    fontPtr->font.underlinePos = fontPtr->underlinePos;
    fontPtr->font.underlineHeight = fontPtr->barHeight;
#endif /* KANJI */
    return fontPtr;
}

/*
 *---------------------------------------------------------------------------
 *
 * GetControlCharSubst --
 *
 *    When displaying text in a widget, a backslashed escape sequence
 *    is substituted for control characters that occur in the text.
 *    Given a control character, fill in a buffer with the replacement
 *    string that should be displayed.
 *
 * Results:
 *    The return value is the length of the substitute string.  buf is
 *    filled with the substitute string; it is not '\0' terminated.
 *
 * Side effects:
 *    None.
 *
 *---------------------------------------------------------------------------
 */

static int
GetControlCharSubst(c, buf)
    int           c;          /* The control character to be replaced. */
    char    buf[4];           /* Buffer that gets replacement string.  It
                         * only needs to be 4 characters long. */
{
    buf[0] = '\\';
    if ((c < sizeof(mapChars)) && (mapChars[c] != 0)) {
      buf[1] = mapChars[c];
      return 2;
    } else {
      buf[1] = 'x';
      buf[2] = hexChars[(c >> 4) & 0xf];
      buf[3] = hexChars[c & 0xf];
      return 4;
    }
}

#ifdef KANJI

void
TkpUpdateCompoundFont(tkFontPtr, faPtr)
     TkFont *tkFontPtr;
     CONST TkFontAttributes *faPtr;
{
    UnixFont *fontPtr = (UnixFont *)tkFontPtr;
    UnixFont *ascii = (UnixFont *)fontPtr->font.asciiFontPtr;
    UnixFont *kanji = (UnixFont *)fontPtr->font.kanjiFontPtr;

    if (ascii == (UnixFont *)NULL) {
      panic("ascii font NULL.");
    }
    if (kanji == NULL) {
      panic("kanji font NULL.");
    }

    if (ascii->font.tabWidth > kanji->font.tabWidth) {
      fontPtr->font.tabWidth = ascii->font.tabWidth;
    } else {
      fontPtr->font.tabWidth = kanji->font.tabWidth;
    }

    if (ABS(ascii->underlinePos) > ABS(kanji->underlinePos)) {
      fontPtr->underlinePos = ascii->underlinePos;
    } else {
      fontPtr->underlinePos = kanji->underlinePos;
    }
    fontPtr->font.underlinePos = fontPtr->underlinePos;

    if (ABS(ascii->barHeight) > ABS(kanji->barHeight)) {
      fontPtr->barHeight = ascii->barHeight;
    } else {
      fontPtr->barHeight = kanji->barHeight;
    }
    fontPtr->font.underlineHeight = fontPtr->barHeight;

    if (ascii->font.fm.ascent > kanji->font.fm.ascent) {
      fontPtr->font.fm.ascent = ascii->font.fm.ascent;
    } else {
      fontPtr->font.fm.ascent = kanji->font.fm.ascent;
    }

    if (ascii->font.fm.descent > kanji->font.fm.descent) {
      fontPtr->font.fm.descent = ascii->font.fm.descent;
    } else {
      fontPtr->font.fm.descent = kanji->font.fm.descent;
    }

    if (ascii->font.fm.maxWidth > kanji->font.fm.maxWidth) {
      fontPtr->font.fm.maxWidth = ascii->font.fm.maxWidth;
    } else {
      fontPtr->font.fm.maxWidth = kanji->font.fm.maxWidth;
    }

    if (ascii->font.fm.fixed != 0 && kanji->font.fm.fixed != 0) {
      fontPtr->font.fm.fixed = kanji->font.fm.fixed;
    }

    if (faPtr != NULL) {
      fontPtr->font.fa.underline  = faPtr->underline;
      fontPtr->font.fa.overstrike = faPtr->overstrike;
      fontPtr->font.fa.pointAdjust = faPtr->pointAdjust;
    }
}

/*
 * tkKinput2.c needs this.
 */

XFontStruct *
TkpGetFontStruct(tkfont)
     Tk_Font tkfont;
{
    return ((UnixFont *)tkfont)->fontStructPtr;
}

XFontStruct *
TkpGetAsciiFontStruct(tkfont)
     Tk_Font tkfont;
{
    return ((UnixFont *)(((UnixFont *)tkfont)->font.asciiFontPtr))->fontStructPtr;
}

XFontStruct *
TkpGetKanjiFontStruct(tkfont)
     Tk_Font tkfont;
{
    return ((UnixFont *)(((UnixFont *)tkfont)->font.kanjiFontPtr))->fontStructPtr;
}
#endif /* KANJI */

Generated by  Doxygen 1.6.0   Back to index