tkUnixFont.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:84k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tkUnixFont.c --
  3.  *
  4.  * Contains the Unix implementation of the platform-independant
  5.  * font package interface.
  6.  *
  7.  * Copyright (c) 1996-1997 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * RCS: @(#) $Id: tkUnixFont.c,v 1.18.2.6 2006/10/05 21:28:17 hobbs Exp $
  13.  */
  14.  
  15. #include "tkUnixInt.h"
  16. #include "tkFont.h"
  17. #include <netinet/in.h> /* for htons() prototype */
  18. #include <arpa/inet.h> /* inet_ntoa() */
  19. /*
  20.  * The preferred font encodings.
  21.  */
  22. static CONST char *encodingList[] = {
  23.     "iso8859-1", "jis0208", "jis0212", NULL
  24. };
  25. /*
  26.  * The following structure represents a font family.  It is assumed that
  27.  * all screen fonts constructed from the same "font family" share certain
  28.  * properties; all screen fonts with the same "font family" point to a
  29.  * shared instance of this structure.  The most important shared property
  30.  * is the character existence metrics, used to determine if a screen font
  31.  * can display a given Unicode character.
  32.  *
  33.  * Under Unix, there are three attributes that uniquely identify a "font
  34.  * family": the foundry, face name, and charset.  
  35.  */
  36. #define FONTMAP_SHIFT 10
  37. #define FONTMAP_PAGES      (1 << (sizeof(Tcl_UniChar)*8 - FONTMAP_SHIFT))
  38. #define FONTMAP_BITSPERPAGE (1 << FONTMAP_SHIFT)
  39. typedef struct FontFamily {
  40.     struct FontFamily *nextPtr; /* Next in list of all known font families. */
  41.     int refCount; /* How many SubFonts are referring to this
  42.  * FontFamily.  When the refCount drops to
  43.  * zero, this FontFamily may be freed. */
  44.     /*
  45.      * Key.
  46.      */
  47.     Tk_Uid foundry; /* Foundry key for this FontFamily. */
  48.     Tk_Uid faceName; /* Face name key for this FontFamily. */
  49.     Tcl_Encoding encoding; /* Encoding key for this FontFamily. */
  50.     /*
  51.      * Derived properties.
  52.      */
  53.     int isTwoByteFont; /* 1 if this is a double-byte font, 0 
  54.  * otherwise. */
  55.     char *fontMap[FONTMAP_PAGES];
  56. /* Two-level sparse table used to determine
  57.  * quickly if the specified character exists.
  58.  * As characters are encountered, more pages
  59.  * in this table are dynamically alloced.  The
  60.  * contents of each page is a bitmask
  61.  * consisting of FONTMAP_BITSPERPAGE bits,
  62.  * representing whether this font can be used
  63.  * to display the given character at the
  64.  * corresponding bit position.  The high bits
  65.  * of the character are used to pick which
  66.  * page of the table is used. */
  67. } FontFamily;
  68. /*
  69.  * The following structure encapsulates an individual screen font.  A font
  70.  * object is made up of however many SubFonts are necessary to display a
  71.  * stream of multilingual characters.
  72.  */
  73. typedef struct SubFont {
  74.     char **fontMap; /* Pointer to font map from the FontFamily, 
  75.  * cached here to save a dereference. */
  76.     XFontStruct *fontStructPtr; /* The specific screen font that will be
  77.  * used when displaying/measuring chars
  78.  * belonging to the FontFamily. */
  79.     FontFamily *familyPtr; /* The FontFamily for this SubFont. */
  80. } SubFont;
  81. /*
  82.  * The following structure represents Unix's implementation of a font
  83.  * object.
  84.  */
  85.  
  86. #define SUBFONT_SPACE 3
  87. #define BASE_CHARS 256
  88. typedef struct UnixFont {
  89.     TkFont font; /* Stuff used by generic font package.  Must
  90.  * be first in structure. */
  91.     SubFont staticSubFonts[SUBFONT_SPACE];
  92. /* Builtin space for a limited number of
  93.  * SubFonts. */
  94.     int numSubFonts; /* Length of following array. */
  95.     SubFont *subFontArray; /* Array of SubFonts that have been loaded
  96.  * in order to draw/measure all the characters
  97.  * encountered by this font so far.  All fonts
  98.  * start off with one SubFont initialized by
  99.  * AllocFont() from the original set of font
  100.  * attributes.  Usually points to
  101.  * staticSubFonts, but may point to malloced
  102.  * space if there are lots of SubFonts. */
  103.     SubFont controlSubFont; /* Font to use to display control-character
  104.  * expansions. */
  105.     Display *display; /* Display that owns font. */
  106.     int pixelSize; /* Original pixel size used when font was
  107.  * constructed. */
  108.     TkXLFDAttributes xa; /* Additional attributes that specify the
  109.  * preferred foundry and encoding to use when
  110.  * constructing additional SubFonts. */
  111.     int widths[BASE_CHARS]; /* Widths of first 256 chars in the base
  112.  * font, for handling common case. */
  113.     int underlinePos; /* Offset from baseline to origin of
  114.  * underline bar (used when drawing underlined
  115.  * font) (pixels). */
  116.     int barHeight; /* Height of underline or overstrike bar
  117.  * (used when drawing underlined or strikeout
  118.  * font) (pixels). */
  119. } UnixFont;
  120. /*
  121.  * The following structure and definition is used to keep track of the
  122.  * alternative names for various encodings.  Asking for an encoding that
  123.  * matches one of the alias patterns will result in actually getting the
  124.  * encoding by its real name.
  125.  */
  126.  
  127. typedef struct EncodingAlias {
  128.     char *realName; /* The real name of the encoding to load if
  129.  * the provided name matched the pattern. */
  130.     char *aliasPattern; /* Pattern for encoding name, of the form
  131.  * that is acceptable to Tcl_StringMatch. */
  132. } EncodingAlias;
  133. /*
  134.  * Just some utility structures used for passing around values in helper
  135.  * procedures.
  136.  */
  137.  
  138. typedef struct FontAttributes {
  139.     TkFontAttributes fa;
  140.     TkXLFDAttributes xa;
  141. } FontAttributes;
  142. typedef struct ThreadSpecificData {
  143.     FontFamily *fontFamilyList; /* The list of font families that are 
  144.  * currently loaded.  As screen fonts
  145.  * are loaded, this list grows to hold 
  146.  * information about what characters
  147.  * exist in each font family. */
  148.     FontFamily controlFamily;   /* FontFamily used to handle control 
  149.  * character expansions.  The encoding
  150.  * of this FontFamily converts UTF-8 to 
  151.  * backslashed escape sequences. */
  152. } ThreadSpecificData;
  153. static Tcl_ThreadDataKey dataKey;
  154. /*
  155.  * The set of builtin encoding alises to convert the XLFD names for the
  156.  * encodings into the names expected by the Tcl encoding package.
  157.  */
  158.  
  159. static EncodingAlias encodingAliases[] = {
  160.     {"gb2312-raw", "gb2312*"},
  161.     {"big5", "big5*"},
  162.     {"cns11643-1", "cns11643*-1"},
  163.     {"cns11643-1", "cns11643*.1-0"},
  164.     {"cns11643-2", "cns11643*-2"},
  165.     {"cns11643-2", "cns11643*.2-0"},
  166.     {"jis0201", "jisx0201*"},
  167.     {"jis0201", "jisx0202*"},
  168.     {"jis0208", "jisc6226*"},
  169.     {"jis0208", "jisx0208*"},
  170.     {"jis0212", "jisx0212*"},
  171.     {"tis620", "tis620*"},
  172.     {"ksc5601", "ksc5601*"},
  173.     {"dingbats", "*dingbats"},
  174. #ifdef WORDS_BIGENDIAN
  175.     {"unicode", "iso10646-1"},
  176. #else
  177.     /*
  178.      * ucs-2be is needed if native order isn't BE.
  179.      */
  180.     {"ucs-2be", "iso10646-1"},
  181. #endif
  182.     {NULL, NULL}
  183. };
  184. /*
  185.  * Procedures used only in this file.
  186.  */
  187. static void FontPkgCleanup _ANSI_ARGS_((ClientData clientData));
  188. static FontFamily * AllocFontFamily _ANSI_ARGS_((Display *display,
  189.     XFontStruct *fontStructPtr, int base));
  190. static SubFont * CanUseFallback _ANSI_ARGS_((UnixFont *fontPtr,
  191.     CONST char *fallbackName, int ch,
  192.     SubFont **fixSubFontPtrPtr));
  193. static SubFont * CanUseFallbackWithAliases _ANSI_ARGS_((
  194.     UnixFont *fontPtr, char *fallbackName,
  195.     int ch, Tcl_DString *nameTriedPtr,
  196.     SubFont **fixSubFontPtrPtr));
  197. static int ControlUtfProc _ANSI_ARGS_((ClientData clientData,
  198.     CONST char *src, int srcLen, int flags,
  199.     Tcl_EncodingState *statePtr, char *dst,
  200.     int dstLen, int *srcReadPtr, int *dstWrotePtr,
  201.     int *dstCharsPtr));
  202. static XFontStruct * CreateClosestFont _ANSI_ARGS_((Tk_Window tkwin,
  203.     CONST TkFontAttributes *faPtr,
  204.     CONST TkXLFDAttributes *xaPtr));
  205. static SubFont * FindSubFontForChar _ANSI_ARGS_((UnixFont *fontPtr,
  206.     int ch, SubFont **fixSubFontPtrPtr));
  207. static void FontMapInsert _ANSI_ARGS_((SubFont *subFontPtr,
  208.     int ch));
  209. static void FontMapLoadPage _ANSI_ARGS_((SubFont *subFontPtr,
  210.     int row));
  211. static int FontMapLookup _ANSI_ARGS_((SubFont *subFontPtr,
  212.     int ch));
  213. static void FreeFontFamily _ANSI_ARGS_((FontFamily *afPtr));
  214. static CONST char * GetEncodingAlias _ANSI_ARGS_((CONST char *name));
  215. static int GetFontAttributes _ANSI_ARGS_((Display *display,
  216.     XFontStruct *fontStructPtr, FontAttributes *faPtr));
  217. static XFontStruct * GetScreenFont _ANSI_ARGS_((Display *display,
  218.     FontAttributes *wantPtr, char **nameList,
  219.     int bestIdx[], unsigned int bestScore[]));
  220. static XFontStruct * GetSystemFont _ANSI_ARGS_((Display *display));
  221. static int IdentifySymbolEncodings _ANSI_ARGS_((
  222.     FontAttributes *faPtr));
  223. static void InitFont _ANSI_ARGS_((Tk_Window tkwin,
  224.     XFontStruct *fontStructPtr, UnixFont *fontPtr));
  225. static void InitSubFont _ANSI_ARGS_((Display *display,
  226.     XFontStruct *fontStructPtr, int base,
  227.     SubFont *subFontPtr));
  228. static char ** ListFonts _ANSI_ARGS_((Display *display,
  229.     CONST char *faceName, int *numNamesPtr));
  230. static char ** ListFontOrAlias _ANSI_ARGS_((Display *display,
  231.     CONST char *faceName, int *numNamesPtr));
  232. static unsigned int RankAttributes _ANSI_ARGS_((FontAttributes *wantPtr,
  233.     FontAttributes *gotPtr));
  234. static void ReleaseFont _ANSI_ARGS_((UnixFont *fontPtr));
  235. static void ReleaseSubFont _ANSI_ARGS_((Display *display, 
  236.     SubFont *subFontPtr));
  237. static int SeenName _ANSI_ARGS_((CONST char *name,
  238.     Tcl_DString *dsPtr));
  239. #ifndef WORDS_BIGENDIAN
  240. static int Ucs2beToUtfProc _ANSI_ARGS_((ClientData clientData,
  241.     CONST char *src, int srcLen, int flags,
  242.     Tcl_EncodingState *statePtr, char *dst, int dstLen,
  243.     int *srcReadPtr, int *dstWrotePtr,
  244.     int *dstCharsPtr));
  245. static int UtfToUcs2beProc _ANSI_ARGS_((ClientData clientData,
  246.     CONST char *src, int srcLen, int flags,
  247.     Tcl_EncodingState *statePtr, char *dst, int dstLen,
  248.     int *srcReadPtr, int *dstWrotePtr,
  249.     int *dstCharsPtr));
  250. #endif
  251. /*
  252.  *-------------------------------------------------------------------------
  253.  *
  254.  * FontPkgCleanup --
  255.  *
  256.  * This procedure is called when an application is created.  It
  257.  * initializes all the structures that are used by the
  258.  * platform-dependent code on a per application basis.
  259.  *
  260.  * Results:
  261.  * None.
  262.  *
  263.  * Side effects:
  264.  * Releases thread-specific resources used by font pkg.
  265.  *
  266.  *-------------------------------------------------------------------------
  267.  */
  268. static void
  269. FontPkgCleanup(ClientData clientData)
  270. {
  271.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  272.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  273.     
  274.     if (tsdPtr->controlFamily.encoding != NULL) {
  275. FontFamily *familyPtr = &tsdPtr->controlFamily;
  276. int i;
  277. Tcl_FreeEncoding(familyPtr->encoding);
  278. for (i = 0; i < FONTMAP_PAGES; i++) {
  279.     if (familyPtr->fontMap[i] != NULL) {
  280. ckfree(familyPtr->fontMap[i]);
  281.     }
  282. }
  283. tsdPtr->controlFamily.encoding = NULL;
  284.     }
  285. }
  286. /*
  287.  *-------------------------------------------------------------------------
  288.  *
  289.  * TkpFontPkgInit --
  290.  *
  291.  * This procedure is called when an application is created.  It
  292.  * initializes all the structures that are used by the
  293.  * platform-dependent code on a per application basis.
  294.  *
  295.  * Results:
  296.  * None.
  297.  *
  298.  * Side effects:
  299.  * None.
  300.  *
  301.  *-------------------------------------------------------------------------
  302.  */
  303. void
  304. TkpFontPkgInit(mainPtr)
  305.     TkMainInfo *mainPtr; /* The application being created. */
  306. {
  307.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  308.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  309.     Tcl_EncodingType type;
  310.     SubFont dummy;
  311.     int i;
  312.     if (tsdPtr->controlFamily.encoding == NULL) {
  313. type.encodingName = "X11ControlChars";
  314. type.toUtfProc = ControlUtfProc;
  315. type.fromUtfProc = ControlUtfProc;
  316. type.freeProc = NULL;
  317. type.clientData = NULL;
  318. type.nullSize = 0;
  319. tsdPtr->controlFamily.refCount = 2;
  320. tsdPtr->controlFamily.encoding = Tcl_CreateEncoding(&type);
  321. tsdPtr->controlFamily.isTwoByteFont = 0;
  322. dummy.familyPtr = &tsdPtr->controlFamily;
  323. dummy.fontMap = tsdPtr->controlFamily.fontMap;
  324. for (i = 0x00; i < 0x20; i++) {
  325.     FontMapInsert(&dummy, i);
  326.     FontMapInsert(&dummy, i + 0x80);
  327. }
  328. #ifndef WORDS_BIGENDIAN
  329. /*
  330.  * UCS-2BE is unicode (UCS-2) in big-endian format.  Define this
  331.  * if native order isn't BE.  It is used in iso10646 fonts.
  332.  */
  333. type.encodingName = "ucs-2be";
  334. type.toUtfProc = Ucs2beToUtfProc;
  335. type.fromUtfProc = UtfToUcs2beProc;
  336. type.freeProc = NULL;
  337. type.clientData = NULL;
  338. type.nullSize = 2;
  339. Tcl_CreateEncoding(&type);
  340. #endif
  341. Tcl_CreateThreadExitHandler(FontPkgCleanup, NULL);
  342.     }
  343. }
  344. /*
  345.  *-------------------------------------------------------------------------
  346.  *
  347.  * ControlUtfProc --
  348.  *
  349.  * Convert from UTF-8 into the ASCII expansion of a control
  350.  * character.
  351.  *
  352.  * Results:
  353.  * Returns TCL_OK if conversion was successful.
  354.  *
  355.  * Side effects:
  356.  * None.
  357.  *
  358.  *-------------------------------------------------------------------------
  359.  */
  360. static int 
  361. ControlUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen,
  362. srcReadPtr, dstWrotePtr, dstCharsPtr)
  363.     ClientData clientData; /* Not used. */
  364.     CONST char *src; /* Source string in UTF-8. */
  365.     int srcLen; /* Source string length in bytes. */
  366.     int flags; /* Conversion control flags. */
  367.     Tcl_EncodingState *statePtr;/* Place for conversion routine to store
  368.  * state information used during a piecewise
  369.  * conversion.  Contents of statePtr are
  370.  * initialized and/or reset by conversion
  371.  * routine under control of flags argument. */
  372.     char *dst; /* Output buffer in which converted string
  373.  * is stored. */
  374.     int dstLen; /* The maximum length of output buffer in
  375.  * bytes. */
  376.     int *srcReadPtr; /* Filled with the number of bytes from the
  377.  * source string that were converted.  This
  378.  * may be less than the original source length
  379.  * if there was a problem converting some
  380.  * source characters. */
  381.     int *dstWrotePtr; /* Filled with the number of bytes that were
  382.  * stored in the output buffer as a result of
  383.  * the conversion. */
  384.     int *dstCharsPtr; /* Filled with the number of characters that
  385.  * correspond to the bytes stored in the
  386.  * output buffer. */
  387. {
  388.     CONST char *srcStart, *srcEnd;
  389.     char *dstStart, *dstEnd;
  390.     Tcl_UniChar ch;
  391.     int result;
  392.     static char hexChars[] = "0123456789abcdef";
  393.     static char mapChars[] = {
  394. 0, 0, 0, 0, 0, 0, 0,
  395. 'a', 'b', 't', 'n', 'v', 'f', 'r'
  396.     };
  397.     result = TCL_OK;
  398.     srcStart = src;
  399.     srcEnd = src + srcLen;
  400.     dstStart = dst;
  401.     dstEnd = dst + dstLen - 6;
  402.     for ( ; src < srcEnd; ) {
  403. if (dst > dstEnd) {
  404.     result = TCL_CONVERT_NOSPACE;
  405.     break;
  406. }
  407. src += Tcl_UtfToUniChar(src, &ch);
  408. dst[0] = '\';
  409. if ((ch < sizeof(mapChars)) && (mapChars[ch] != 0)) {
  410.     dst[1] = mapChars[ch];
  411.     dst += 2;
  412. } else if (ch < 256) {
  413.     dst[1] = 'x';
  414.     dst[2] = hexChars[(ch >> 4) & 0xf];
  415.     dst[3] = hexChars[ch & 0xf];
  416.     dst += 4;
  417. } else {
  418.     dst[1] = 'u';
  419.     dst[2] = hexChars[(ch >> 12) & 0xf];
  420.     dst[3] = hexChars[(ch >> 8) & 0xf];
  421.     dst[4] = hexChars[(ch >> 4) & 0xf];
  422.     dst[5] = hexChars[ch & 0xf];
  423.     dst += 6;
  424. }
  425.     }
  426.     *srcReadPtr = src - srcStart;
  427.     *dstWrotePtr = dst - dstStart;
  428.     *dstCharsPtr = dst - dstStart;
  429.     return result;
  430. }
  431. #ifndef WORDS_BIGENDIAN
  432. /*
  433.  *-------------------------------------------------------------------------
  434.  *
  435.  * Ucs2beToUtfProc --
  436.  *
  437.  * Convert from UCS-2BE (big-endian 16-bit Unicode) to UTF-8.
  438.  * This is only defined on LE machines.
  439.  *
  440.  * Results:
  441.  * Returns TCL_OK if conversion was successful.
  442.  *
  443.  * Side effects:
  444.  * None.
  445.  *
  446.  *-------------------------------------------------------------------------
  447.  */
  448. static int 
  449. Ucs2beToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen,
  450. srcReadPtr, dstWrotePtr, dstCharsPtr)
  451.     ClientData clientData; /* Not used. */
  452.     CONST char *src; /* Source string in Unicode. */
  453.     int srcLen; /* Source string length in bytes. */
  454.     int flags; /* Conversion control flags. */
  455.     Tcl_EncodingState *statePtr;/* Place for conversion routine to store
  456.  * state information used during a piecewise
  457.  * conversion.  Contents of statePtr are
  458.  * initialized and/or reset by conversion
  459.  * routine under control of flags argument. */
  460.     char *dst; /* Output buffer in which converted string
  461.  * is stored. */
  462.     int dstLen; /* The maximum length of output buffer in
  463.  * bytes. */
  464.     int *srcReadPtr; /* Filled with the number of bytes from the
  465.  * source string that were converted.  This
  466.  * may be less than the original source length
  467.  * if there was a problem converting some
  468.  * source characters. */
  469.     int *dstWrotePtr; /* Filled with the number of bytes that were
  470.  * stored in the output buffer as a result of
  471.  * the conversion. */
  472.     int *dstCharsPtr; /* Filled with the number of characters that
  473.  * correspond to the bytes stored in the
  474.  * output buffer. */
  475. {
  476.     CONST char *srcStart, *srcEnd;
  477.     char *dstEnd, *dstStart;
  478.     int result, numChars;
  479.     result = TCL_OK;
  480.     /* check alignment with ucs-2 (2 == sizeof(UCS-2)) */
  481.     if ((srcLen % 2) != 0) {
  482. result = TCL_CONVERT_MULTIBYTE;
  483. srcLen--;
  484.     }
  485.     srcStart = src;
  486.     srcEnd = src + srcLen;
  487.     dstStart = dst;
  488.     dstEnd = dst + dstLen - TCL_UTF_MAX;
  489.     for (numChars = 0; src < srcEnd; numChars++) {
  490. if (dst > dstEnd) {
  491.     result = TCL_CONVERT_NOSPACE;
  492.     break;
  493. }
  494. /*
  495.  * Need to swap byte-order on little-endian machines (x86) for
  496.  * UCS-2BE.  We know this is an LE->BE swap.
  497.  */
  498. dst += Tcl_UniCharToUtf(htons(*((short *)src)), dst);
  499. src += 2 /* sizeof(UCS-2) */;
  500.     }
  501.     *srcReadPtr = src - srcStart;
  502.     *dstWrotePtr = dst - dstStart;
  503.     *dstCharsPtr = numChars;
  504.     return result;
  505. }
  506. /*
  507.  *-------------------------------------------------------------------------
  508.  *
  509.  * UtfToUcs2beProc --
  510.  *
  511.  * Convert from UTF-8 to UCS-2BE (fixed 2-byte encoding).
  512.  *
  513.  * Results:
  514.  * Returns TCL_OK if conversion was successful.
  515.  *
  516.  * Side effects:
  517.  * None.
  518.  *
  519.  *-------------------------------------------------------------------------
  520.  */
  521. static int 
  522. UtfToUcs2beProc(clientData, src, srcLen, flags, statePtr, dst, dstLen,
  523. srcReadPtr, dstWrotePtr, dstCharsPtr)
  524.     ClientData clientData; /* TableEncodingData that specifies encoding. */
  525.     CONST char *src; /* Source string in UTF-8. */
  526.     int srcLen; /* Source string length in bytes. */
  527.     int flags; /* Conversion control flags. */
  528.     Tcl_EncodingState *statePtr;/* Place for conversion routine to store
  529.  * state information used during a piecewise
  530.  * conversion.  Contents of statePtr are
  531.  * initialized and/or reset by conversion
  532.  * routine under control of flags argument. */
  533.     char *dst; /* Output buffer in which converted string
  534.  * is stored. */
  535.     int dstLen; /* The maximum length of output buffer in
  536.  * bytes. */
  537.     int *srcReadPtr; /* Filled with the number of bytes from the
  538.  * source string that were converted.  This
  539.  * may be less than the original source length
  540.  * if there was a problem converting some
  541.  * source characters. */
  542.     int *dstWrotePtr; /* Filled with the number of bytes that were
  543.  * stored in the output buffer as a result of
  544.  * the conversion. */
  545.     int *dstCharsPtr; /* Filled with the number of characters that
  546.  * correspond to the bytes stored in the
  547.  * output buffer. */
  548. {
  549.     CONST char *srcStart, *srcEnd, *srcClose, *dstStart, *dstEnd;
  550.     int result, numChars;
  551.     Tcl_UniChar ch;
  552.     srcStart = src;
  553.     srcEnd = src + srcLen;
  554.     srcClose = srcEnd;
  555.     if ((flags & TCL_ENCODING_END) == 0) {
  556. srcClose -= TCL_UTF_MAX;
  557.     }
  558.     dstStart = dst;
  559.     dstEnd   = dst + dstLen - 2 /* sizeof(UCS-2) */;
  560.     result = TCL_OK;
  561.     for (numChars = 0; src < srcEnd; numChars++) {
  562. if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) {
  563.     /*
  564.      * If there is more string to follow, this will ensure that the
  565.      * last UTF-8 character in the source buffer hasn't been cut off.
  566.      */
  567.     result = TCL_CONVERT_MULTIBYTE;
  568.     break;
  569. }
  570. if (dst > dstEnd) {
  571.     result = TCL_CONVERT_NOSPACE;
  572.     break;
  573.         }
  574. src += Tcl_UtfToUniChar(src, &ch);
  575. /*
  576.  * Ensure big-endianness (store big bits first).
  577.  * XXX: This hard-codes the assumed size of Tcl_UniChar as 2.
  578.  * Make sure to work in char* for Tcl_UtfToUniChar alignment.
  579.  * [Bug 1122671]
  580.  */
  581. *dst++ = (ch >> 8);
  582. *dst++ = (ch & 0xFF);
  583.     }
  584.     *srcReadPtr = src - srcStart;
  585.     *dstWrotePtr = dst - dstStart;
  586.     *dstCharsPtr = numChars;
  587.     return result;
  588. }
  589. #endif /* WORDS_BIGENDIAN */
  590. /*
  591.  *---------------------------------------------------------------------------
  592.  *
  593.  * TkpGetNativeFont --
  594.  *
  595.  * Map a platform-specific native font name to a TkFont.
  596.  *
  597.  * Results:
  598.  *  The return value is a pointer to a TkFont that represents the
  599.  * native font.  If a native font by the given name could not be
  600.  * found, the return value is NULL.  
  601.  *
  602.  * Every call to this procedure returns a new TkFont structure,
  603.  * even if the name has already been seen before.  The caller should
  604.  * call TkpDeleteFont() when the font is no longer needed.
  605.  *
  606.  * The caller is responsible for initializing the memory associated
  607.  * with the generic TkFont when this function returns and releasing
  608.  * the contents of the generic TkFont before calling TkpDeleteFont().
  609.  *
  610.  * Side effects:
  611.  * Memory allocated.
  612.  *
  613.  *---------------------------------------------------------------------------
  614.  */
  615.  
  616. TkFont *
  617. TkpGetNativeFont(tkwin, name)
  618.     Tk_Window tkwin; /* For display where font will be used. */
  619.     CONST char *name; /* Platform-specific font name. */
  620. {
  621.     UnixFont *fontPtr;
  622.     XFontStruct *fontStructPtr;
  623.     FontAttributes fa;
  624.     CONST char *p;
  625.     int hasSpace, dashes, hasWild;
  626.     /*
  627.      * The behavior of X when given a name that isn't an XLFD is unspecified.
  628.      * For example, Exceed 6 returns a valid font for any random string. This
  629.      * is awkward since system names have higher priority than the other Tk
  630.      * font syntaxes.  So, we need to perform a quick sanity check on the
  631.      * name and fail if it looks suspicious.  We fail if the name:
  632.      *     - contains a space immediately before a dash
  633.      *    - contains a space, but no '*' characters and fewer than 14 dashes
  634.      */
  635.     hasSpace = dashes = hasWild = 0;
  636.     for (p = name; *p != ''; p++) {
  637. if (*p == ' ') {
  638.     if (p[1] == '-') {
  639. return NULL;
  640.     }
  641.     hasSpace = 1;
  642. } else if (*p == '-') {
  643.     dashes++;
  644. } else if (*p == '*') {
  645.     hasWild = 1;
  646. }
  647.     }
  648.     if ((dashes < 14) && !hasWild && hasSpace) {
  649. return NULL;
  650.     }
  651.     fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), name);
  652.     if (fontStructPtr == NULL) {
  653. /*
  654.  * Handle all names that look like XLFDs here.  Otherwise, when
  655.  * TkpGetFontFromAttributes is called from generic code, any
  656.  * foundry or encoding information specified in the XLFD will have
  657.  * been parsed out and lost.  But make sure we don't have an
  658.  * "-option value" string since TkFontParseXLFD would return a
  659.  * false success when attempting to parse it.
  660.  */
  661. if (name[0] == '-') {
  662.     if (name[1] != '*') {
  663. char *dash;
  664. dash = strchr(name + 1, '-');
  665. if ((dash == NULL) || (isspace(UCHAR(dash[-1])))) {
  666.     return NULL;
  667. }
  668.     }
  669. } else if (name[0] != '*') {
  670.     return NULL;
  671. }
  672. if (TkFontParseXLFD(name, &fa.fa, &fa.xa) != TCL_OK) {
  673.     return NULL;
  674. }
  675. fontStructPtr = CreateClosestFont(tkwin, &fa.fa, &fa.xa);
  676.     }
  677.     fontPtr = (UnixFont *) ckalloc(sizeof(UnixFont));
  678.     InitFont(tkwin, fontStructPtr, fontPtr);
  679.     return (TkFont *) fontPtr;
  680. }
  681. /*
  682.  *---------------------------------------------------------------------------
  683.  *
  684.  * TkpGetFontFromAttributes -- 
  685.  *
  686.  * Given a desired set of attributes for a font, find a font with
  687.  * the closest matching attributes.
  688.  *
  689.  * Results:
  690.  *  The return value is a pointer to a TkFont that represents the
  691.  * font with the desired attributes.  If a font with the desired
  692.  * attributes could not be constructed, some other font will be
  693.  * substituted automatically.
  694.  *
  695.  * Every call to this procedure returns a new TkFont structure,
  696.  * even if the specified attributes have already been seen before.
  697.  * The caller should call TkpDeleteFont() to free the platform-
  698.  * specific data when the font is no longer needed.  
  699.  *
  700.  * The caller is responsible for initializing the memory associated
  701.  * with the generic TkFont when this function returns and releasing
  702.  * the contents of the generic TkFont before calling TkpDeleteFont().
  703.  *
  704.  * Side effects:
  705.  * Memory allocated.
  706.  *
  707.  *---------------------------------------------------------------------------
  708.  */
  709. TkFont *
  710. TkpGetFontFromAttributes(tkFontPtr, tkwin, faPtr)
  711.     TkFont *tkFontPtr; /* If non-NULL, store the information in
  712.  * this existing TkFont structure, rather than
  713.  * allocating a new structure to hold the
  714.  * font; the existing contents of the font
  715.  * will be released.  If NULL, a new TkFont
  716.  * structure is allocated. */
  717.     Tk_Window tkwin; /* For display where font will be used. */
  718.     CONST TkFontAttributes *faPtr;
  719. /* Set of attributes to match. */
  720. {
  721.     UnixFont *fontPtr;
  722.     TkXLFDAttributes xa;
  723.     XFontStruct *fontStructPtr;
  724.     TkInitXLFDAttributes(&xa);
  725.     fontStructPtr = CreateClosestFont(tkwin, faPtr, &xa);
  726.     fontPtr = (UnixFont *) tkFontPtr;
  727.     if (fontPtr == NULL) {
  728. fontPtr = (UnixFont *) ckalloc(sizeof(UnixFont));
  729.     } else {
  730. ReleaseFont(fontPtr);
  731.     }
  732.     InitFont(tkwin, fontStructPtr, fontPtr);
  733.     fontPtr->font.fa.underline = faPtr->underline;
  734.     fontPtr->font.fa.overstrike = faPtr->overstrike;
  735.     return (TkFont *) fontPtr;
  736. }
  737. /*
  738.  *---------------------------------------------------------------------------
  739.  *
  740.  * TkpDeleteFont --
  741.  *
  742.  * Called to release a font allocated by TkpGetNativeFont() or
  743.  * TkpGetFontFromAttributes().  The caller should have already
  744.  * released the fields of the TkFont that are used exclusively by
  745.  * the generic TkFont code.
  746.  *
  747.  * Results:
  748.  * None.
  749.  *
  750.  * Side effects:
  751.  * TkFont is deallocated.
  752.  *
  753.  *---------------------------------------------------------------------------
  754.  */
  755. void
  756. TkpDeleteFont(tkFontPtr)
  757.     TkFont *tkFontPtr; /* Token of font to be deleted. */
  758. {
  759.     UnixFont *fontPtr;
  760.     fontPtr = (UnixFont *) tkFontPtr;
  761.     ReleaseFont(fontPtr);
  762. }
  763. /*
  764.  *---------------------------------------------------------------------------
  765.  *
  766.  * TkpGetFontFamilies --
  767.  *
  768.  * Return information about the font families that are available
  769.  * on the display of the given window.
  770.  *
  771.  * Results:
  772.  * Modifies interp's result object to hold a list of all the available
  773.  * font families.
  774.  *
  775.  * Side effects:
  776.  * None.
  777.  *
  778.  *---------------------------------------------------------------------------
  779.  */
  780. void
  781. TkpGetFontFamilies(interp, tkwin)
  782.     Tcl_Interp *interp; /* Interp to hold result. */
  783.     Tk_Window tkwin; /* For display to query. */
  784. {
  785.     int i, new, numNames;
  786.     char *family;
  787.     Tcl_HashTable familyTable;
  788.     Tcl_HashEntry *hPtr;
  789.     Tcl_HashSearch search;
  790.     char **nameList;
  791.     Tcl_Obj *resultPtr, *strPtr;
  792.     resultPtr = Tcl_GetObjResult(interp);    
  793.     Tcl_InitHashTable(&familyTable, TCL_STRING_KEYS);
  794.     nameList = ListFonts(Tk_Display(tkwin), "*", &numNames);
  795.     for (i = 0; i < numNames; i++) {
  796. char *familyEnd;
  797. family = strchr(nameList[i] + 1, '-');
  798. if (family == NULL) {
  799.     /*
  800.      * Apparently, sometimes ListFonts() can return a font name with
  801.      * zero or one '-' character in it. This is probably indicative of
  802.      * a server misconfiguration, but crashing because of it is a very
  803.      * bad idea anyway. [Bug 1475865]
  804.      */
  805.     continue;
  806. }
  807. family++; /* Advance to char after '-'. */
  808. familyEnd = strchr(family, '-');
  809. if (familyEnd == NULL) {
  810.     continue; /* See comment above. */
  811. }
  812. *familyEnd = '';
  813. family = strchr(nameList[i] + 1, '-') + 1;
  814. Tcl_CreateHashEntry(&familyTable, family, &new);
  815.     }
  816.     XFreeFontNames(nameList);
  817.     hPtr = Tcl_FirstHashEntry(&familyTable, &search);
  818.     while (hPtr != NULL) {
  819. strPtr = Tcl_NewStringObj(Tcl_GetHashKey(&familyTable, hPtr), -1); 
  820. Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);
  821. hPtr = Tcl_NextHashEntry(&search);
  822.     }
  823.     Tcl_DeleteHashTable(&familyTable);
  824. }
  825. /*
  826.  *-------------------------------------------------------------------------
  827.  *
  828.  * TkpGetSubFonts --
  829.  *
  830.  * A function used by the testing package for querying the actual 
  831.  * screen fonts that make up a font object.
  832.  *
  833.  * Results:
  834.  * Modifies interp's result object to hold a list containing the 
  835.  * names of the screen fonts that make up the given font object.
  836.  *
  837.  * Side effects:
  838.  * None.
  839.  *
  840.  *-------------------------------------------------------------------------
  841.  */
  842. void
  843. TkpGetSubFonts(interp, tkfont)
  844.     Tcl_Interp *interp;
  845.     Tk_Font tkfont;
  846. {
  847.     int i;
  848.     Tcl_Obj *objv[3];
  849.     Tcl_Obj *resultPtr, *listPtr;
  850.     UnixFont *fontPtr;
  851.     FontFamily *familyPtr;
  852.     resultPtr = Tcl_GetObjResult(interp);    
  853.     fontPtr = (UnixFont *) tkfont;
  854.     for (i = 0; i < fontPtr->numSubFonts; i++) {
  855. familyPtr = fontPtr->subFontArray[i].familyPtr;
  856. objv[0] = Tcl_NewStringObj(familyPtr->faceName, -1);
  857. objv[1] = Tcl_NewStringObj(familyPtr->foundry, -1);
  858. objv[2] = Tcl_NewStringObj(Tcl_GetEncodingName(familyPtr->encoding), -1);
  859. listPtr = Tcl_NewListObj(3, objv);
  860. Tcl_ListObjAppendElement(NULL, resultPtr, listPtr);
  861.     }
  862. }
  863. /*
  864.  *---------------------------------------------------------------------------
  865.  *
  866.  *  Tk_MeasureChars --
  867.  *
  868.  * Determine the number of characters from the string that will fit
  869.  * in the given horizontal span.  The measurement is done under the
  870.  * assumption that Tk_DrawChars() will be used to actually display
  871.  * the characters.
  872.  *
  873.  * Results:
  874.  * The return value is the number of bytes from source that
  875.  * fit into the span that extends from 0 to maxLength.  *lengthPtr is
  876.  * filled with the x-coordinate of the right edge of the last
  877.  * character that did fit.
  878.  *
  879.  * Side effects:
  880.  * None.
  881.  *
  882.  *---------------------------------------------------------------------------
  883.  */
  884. int
  885. Tk_MeasureChars(tkfont, source, numBytes, maxLength, flags, lengthPtr)
  886.     Tk_Font tkfont; /* Font in which characters will be drawn. */
  887.     CONST char *source; /* UTF-8 string to be displayed.  Need not be
  888.  * '' terminated. */
  889.     int numBytes; /* Maximum number of bytes to consider
  890.  * from source string. */
  891.     int maxLength; /* If >= 0, maxLength specifies the longest
  892.  * permissible line length in pixels; don't
  893.  * consider any character that would cross
  894.  * this x-position.  If < 0, then line length
  895.  * is unbounded and the flags argument is
  896.  * ignored. */
  897.     int flags; /* Various flag bits OR-ed together:
  898.  * TK_PARTIAL_OK means include the last char
  899.  * which only partially fit on this line.
  900.  * TK_WHOLE_WORDS means stop on a word
  901.  * boundary, if possible.
  902.  * TK_AT_LEAST_ONE means return at least one
  903.  * character even if no characters fit. */
  904.     int *lengthPtr; /* Filled with x-location just after the
  905.  * terminating character. */
  906. {
  907.     UnixFont *fontPtr;
  908.     SubFont *lastSubFontPtr;
  909.     int curX, curByte;
  910.     /*
  911.      * Unix does not use kerning or fractional character widths when
  912.      * displaying text on the screen.  So that means we can safely measure
  913.      * individual characters or spans of characters and add up the widths
  914.      * w/o any "off-by-one-pixel" errors.
  915.      */
  916.     fontPtr = (UnixFont *) tkfont;
  917.     lastSubFontPtr = &fontPtr->subFontArray[0];
  918.     if (numBytes == 0) {
  919. curX = 0;
  920. curByte = 0;
  921.     } else if (maxLength < 0) {
  922. CONST char *p, *end, *next;
  923. Tcl_UniChar ch;
  924. SubFont *thisSubFontPtr;
  925. FontFamily *familyPtr;
  926. Tcl_DString runString;
  927. /*
  928.  * A three step process:
  929.  * 1. Find a contiguous range of characters that can all be 
  930.  *    represented by a single screen font.
  931.  * 2. Convert those chars to the encoding of that font.
  932.  * 3. Measure converted chars.
  933.  */
  934. curX = 0;
  935. end = source + numBytes;
  936. for (p = source; p < end; ) {
  937.     next = p + Tcl_UtfToUniChar(p, &ch);
  938.     thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
  939.     if (thisSubFontPtr != lastSubFontPtr) {
  940. familyPtr = lastSubFontPtr->familyPtr;
  941. Tcl_UtfToExternalDString(familyPtr->encoding, source,
  942. p - source, &runString);
  943. if (familyPtr->isTwoByteFont) {
  944.     curX += XTextWidth16(lastSubFontPtr->fontStructPtr,
  945.     (XChar2b *) Tcl_DStringValue(&runString),
  946.     Tcl_DStringLength(&runString) / 2);
  947. } else {
  948.     curX += XTextWidth(lastSubFontPtr->fontStructPtr,
  949.     Tcl_DStringValue(&runString),
  950.     Tcl_DStringLength(&runString));
  951. }
  952. Tcl_DStringFree(&runString);
  953. lastSubFontPtr = thisSubFontPtr;
  954. source = p;
  955.     }
  956.     p = next;
  957. }
  958. familyPtr = lastSubFontPtr->familyPtr;
  959. Tcl_UtfToExternalDString(familyPtr->encoding, source,  p - source,
  960. &runString);
  961. if (familyPtr->isTwoByteFont) {
  962.     curX += XTextWidth16(lastSubFontPtr->fontStructPtr,
  963.     (XChar2b *) Tcl_DStringValue(&runString),
  964.     Tcl_DStringLength(&runString) >> 1);
  965. } else {
  966.     curX += XTextWidth(lastSubFontPtr->fontStructPtr,
  967.     Tcl_DStringValue(&runString),
  968.     Tcl_DStringLength(&runString));
  969. }
  970. Tcl_DStringFree(&runString);
  971. curByte = numBytes;
  972.     } else {
  973. CONST char *p, *end, *next, *term;
  974. int newX, termX, sawNonSpace, dstWrote;
  975. Tcl_UniChar ch;
  976. FontFamily *familyPtr;
  977. char buf[16];
  978. /*
  979.  * How many chars will fit in the space allotted? 
  980.  * This first version may be inefficient because it measures
  981.  * every character individually.
  982.  */
  983. next = source + Tcl_UtfToUniChar(source, &ch);
  984. newX = curX = termX = 0;
  985. term = source;
  986. end = source + numBytes;
  987. sawNonSpace = (ch > 255) || !isspace(ch);
  988. familyPtr = lastSubFontPtr->familyPtr;
  989. for (p = source; ; ) {
  990.     if ((ch < BASE_CHARS) && (fontPtr->widths[ch] != 0)) {
  991. newX += fontPtr->widths[ch];
  992.     } else {
  993. lastSubFontPtr = FindSubFontForChar(fontPtr, ch, NULL);
  994. familyPtr = lastSubFontPtr->familyPtr;
  995. Tcl_UtfToExternal(NULL, familyPtr->encoding, p, next - p,
  996. 0, NULL, buf, sizeof(buf), NULL, &dstWrote, NULL);
  997. if (familyPtr->isTwoByteFont) {
  998.     newX += XTextWidth16(lastSubFontPtr->fontStructPtr,
  999.     (XChar2b *) buf, dstWrote >> 1);
  1000. } else {
  1001.     newX += XTextWidth(lastSubFontPtr->fontStructPtr, buf,
  1002.     dstWrote);
  1003. }
  1004.     }
  1005.     if (newX > maxLength) {
  1006. break;
  1007.     }
  1008.     curX = newX;
  1009.     p = next;
  1010.     if (p >= end) {
  1011. term = end;
  1012. termX = curX;
  1013. break;
  1014.     }
  1015.     next += Tcl_UtfToUniChar(next, &ch);
  1016.     if ((ch < 256) && isspace(ch)) {
  1017. if (sawNonSpace) {
  1018.     term = p;
  1019.     termX = curX;
  1020.     sawNonSpace = 0;
  1021. }
  1022.     } else {
  1023. sawNonSpace = 1;
  1024.     }
  1025. }
  1026. /*
  1027.  * P points to the first character that doesn't fit in the desired
  1028.  * span.  Use the flags to figure out what to return.
  1029.  */
  1030. if ((flags & TK_PARTIAL_OK) && (p < end) && (curX < maxLength)) {
  1031.     /*
  1032.      * Include the first character that didn't quite fit in the desired
  1033.      * span.  The width returned will include the width of that extra
  1034.      * character.
  1035.      */
  1036.     curX = newX;
  1037.     p += Tcl_UtfToUniChar(p, &ch);
  1038. }
  1039. if ((flags & TK_AT_LEAST_ONE) && (term == source) && (p < end)) {
  1040.     term = p;
  1041.     termX = curX;
  1042.     if (term == source) {
  1043. term += Tcl_UtfToUniChar(term, &ch);
  1044. termX = newX;
  1045.     }
  1046. } else if ((p >= end) || !(flags & TK_WHOLE_WORDS)) {
  1047.     term = p;
  1048.     termX = curX;
  1049. }
  1050. curX = termX;
  1051. curByte = term - source;
  1052.     }
  1053.     *lengthPtr = curX;
  1054.     return curByte;
  1055. }
  1056. /*
  1057.  *---------------------------------------------------------------------------
  1058.  *
  1059.  * Tk_DrawChars --
  1060.  *
  1061.  * Draw a string of characters on the screen.  Tk_DrawChars()
  1062.  * expands control characters that occur in the string to 
  1063.  * xNN sequences.  
  1064.  *
  1065.  * Results:
  1066.  * None.
  1067.  *
  1068.  * Side effects:
  1069.  * Information gets drawn on the screen.
  1070.  *
  1071.  *---------------------------------------------------------------------------
  1072.  */
  1073. void
  1074. Tk_DrawChars(display, drawable, gc, tkfont, source, numBytes, x, y)
  1075.     Display *display; /* Display on which to draw. */
  1076.     Drawable drawable; /* Window or pixmap in which to draw. */
  1077.     GC gc; /* Graphics context for drawing characters. */
  1078.     Tk_Font tkfont; /* Font in which characters will be drawn;
  1079.  * must be the same as font used in GC. */
  1080.     CONST char *source; /* UTF-8 string to be displayed.  Need not be
  1081.  * '' terminated.  All Tk meta-characters
  1082.  * (tabs, control characters, and newlines)
  1083.  * should be stripped out of the string that
  1084.  * is passed to this function.  If they are
  1085.  * not stripped out, they will be displayed as
  1086.  * regular printing characters. */
  1087.     int numBytes; /* Number of bytes in string. */
  1088.     int x, y; /* Coordinates at which to place origin of
  1089.  * string when drawing. */
  1090. {
  1091.     UnixFont *fontPtr;
  1092.     SubFont *thisSubFontPtr, *lastSubFontPtr;
  1093.     Tcl_DString runString;
  1094.     CONST char *p, *end, *next;
  1095.     int xStart, needWidth, window_width, do_width;
  1096.     Tcl_UniChar ch;
  1097.     FontFamily *familyPtr;
  1098. #ifdef TK_DRAW_CHAR_XWINDOW_CHECK
  1099.     int rx, ry;
  1100.     unsigned int width, height, border_width, depth;
  1101.     Drawable root;
  1102. #endif
  1103.     fontPtr = (UnixFont *) tkfont;
  1104.     lastSubFontPtr = &fontPtr->subFontArray[0];
  1105.     xStart = x;
  1106. #ifdef TK_DRAW_CHAR_XWINDOW_CHECK
  1107.     /*
  1108.      * Get the window width so we can abort drawing outside of the window
  1109.      */
  1110.     if (XGetGeometry(display, drawable, &root, &rx, &ry, &width, &height,
  1111.     &border_width, &depth) == False) {
  1112. window_width = INT_MAX;
  1113.     } else {
  1114. window_width = width;
  1115.     }
  1116. #else
  1117.     /*
  1118.      * This is used by default until we find a solution that doesn't
  1119.      * round-trip to the X server (need to get Tk cached window width).
  1120.      */
  1121.     window_width = 32768;
  1122. #endif
  1123.     end = source + numBytes;
  1124.     needWidth = fontPtr->font.fa.underline + fontPtr->font.fa.overstrike;
  1125.     for (p = source; p <= end; ) {
  1126. if (p < end) {
  1127.     next = p + Tcl_UtfToUniChar(p, &ch);
  1128.     thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
  1129. } else {
  1130.     next = p + 1;
  1131.     thisSubFontPtr = lastSubFontPtr;
  1132. }
  1133. if ((thisSubFontPtr != lastSubFontPtr)
  1134. || (p == end) || (p-source > 200)) {
  1135.     if (p > source) {
  1136.         do_width = (needWidth || (p != end)) ? 1 : 0;
  1137. familyPtr = lastSubFontPtr->familyPtr;
  1138. Tcl_UtfToExternalDString(familyPtr->encoding, source,
  1139. p - source, &runString);
  1140. if (familyPtr->isTwoByteFont) {
  1141.     XDrawString16(display, drawable, gc, x, y, 
  1142.     (XChar2b *) Tcl_DStringValue(&runString),
  1143.     Tcl_DStringLength(&runString) / 2);
  1144.     if (do_width) {
  1145. x += XTextWidth16(lastSubFontPtr->fontStructPtr,
  1146. (XChar2b *) Tcl_DStringValue(&runString),
  1147. Tcl_DStringLength(&runString) / 2);
  1148.     }
  1149. } else {
  1150.     XDrawString(display, drawable, gc, x, y,
  1151.     Tcl_DStringValue(&runString),
  1152.     Tcl_DStringLength(&runString));
  1153.     if (do_width) {
  1154. x += XTextWidth(lastSubFontPtr->fontStructPtr,
  1155. Tcl_DStringValue(&runString),
  1156. Tcl_DStringLength(&runString));
  1157.     }
  1158. }
  1159. Tcl_DStringFree(&runString);
  1160.     }
  1161.     lastSubFontPtr = thisSubFontPtr;
  1162.     source = p;
  1163.     XSetFont(display, gc, lastSubFontPtr->fontStructPtr->fid);
  1164.     if (x > window_width) {
  1165.         break;
  1166.     }
  1167. }
  1168. p = next;
  1169.     }
  1170.     if (lastSubFontPtr != &fontPtr->subFontArray[0]) {
  1171. XSetFont(display, gc, fontPtr->subFontArray[0].fontStructPtr->fid);
  1172.     }
  1173.     if (fontPtr->font.fa.underline != 0) {
  1174. XFillRectangle(display, drawable, gc, xStart,
  1175. y + fontPtr->underlinePos,
  1176. (unsigned) (x - xStart), (unsigned) fontPtr->barHeight);
  1177.     }
  1178.     if (fontPtr->font.fa.overstrike != 0) {
  1179. y -= fontPtr->font.fm.descent + (fontPtr->font.fm.ascent) / 10;
  1180. XFillRectangle(display, drawable, gc, xStart, y,
  1181. (unsigned) (x - xStart), (unsigned) fontPtr->barHeight);
  1182.     }
  1183. }
  1184. /*
  1185.  *-------------------------------------------------------------------------
  1186.  *
  1187.  * CreateClosestFont --
  1188.  *
  1189.  * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().
  1190.  * Given a set of font attributes, construct a close XFontStruct.
  1191.  * If requested face name is not available, automatically
  1192.  * substitutes an alias for requested face name.  If encoding is
  1193.  * not specified (or the requested one is not available),
  1194.  * automatically chooses another encoding from the list of
  1195.  * preferred encodings.  If the foundry is not specified (or
  1196.  * is not available) automatically prefers "adobe" foundry.
  1197.  * For all other attributes, if the requested value was not
  1198.  * available, the appropriate "close" value will be used.
  1199.  *
  1200.  * Results:
  1201.  * Return value is the XFontStruct that best matched the
  1202.  * requested attributes.  The return value is never NULL; some
  1203.  * font will always be returned.
  1204.  *
  1205.  * Side effects:
  1206.  * None.
  1207.  *
  1208.  *-------------------------------------------------------------------------
  1209.  */
  1210. static XFontStruct *
  1211. CreateClosestFont(tkwin, faPtr, xaPtr)
  1212.     Tk_Window tkwin; /* For display where font will be used. */
  1213.     CONST TkFontAttributes *faPtr;
  1214. /* Set of generic attributes to match. */
  1215.     CONST TkXLFDAttributes *xaPtr;
  1216. /* Set of X-specific attributes to match. */
  1217. {
  1218.     FontAttributes want;
  1219.     char **nameList;
  1220.     int numNames, nameIdx;
  1221.     Display *display;
  1222.     XFontStruct *fontStructPtr;
  1223.     int bestIdx[2];
  1224.     unsigned int bestScore[2];
  1225.     want.fa = *faPtr;
  1226.     want.xa = *xaPtr;
  1227.     if (want.xa.foundry == NULL) {
  1228. want.xa.foundry = Tk_GetUid("adobe");
  1229.     }
  1230.     if (want.fa.family == NULL) {
  1231. want.fa.family = Tk_GetUid("fixed");
  1232.     }
  1233.     want.fa.size = -TkFontGetPixels(tkwin, faPtr->size);
  1234.     if (want.xa.charset == NULL || *want.xa.charset == '') {
  1235. want.xa.charset = Tk_GetUid("iso8859-1"); /* locale. */
  1236.     }
  1237.     display = Tk_Display(tkwin);
  1238.     /*
  1239.      * Algorithm to get the closest font to the name requested.
  1240.      *
  1241.      * try fontname
  1242.      * try all aliases for fontname
  1243.      * foreach fallback for fontname
  1244.      *     try the fallback
  1245.      *     try all aliases for the fallback
  1246.      */
  1247.     nameList = ListFontOrAlias(display, want.fa.family, &numNames);
  1248.     if (numNames == 0) {
  1249. char ***fontFallbacks;
  1250. int i, j;
  1251. char *fallback;
  1252. fontFallbacks = TkFontGetFallbacks();
  1253. for (i = 0; fontFallbacks[i] != NULL; i++) {
  1254.     for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {
  1255. if (strcasecmp(want.fa.family, fallback) == 0) {
  1256.     break;
  1257. }
  1258.     }
  1259.     if (fallback != NULL) {
  1260. for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {
  1261.     nameList = ListFontOrAlias(display, fallback, &numNames);
  1262.     if (numNames != 0) {
  1263. goto found;
  1264.     }
  1265. }
  1266.     }
  1267. }
  1268. nameList = ListFonts(display, "fixed", &numNames);
  1269. if (numNames == 0) {
  1270.     nameList = ListFonts(display, "*", &numNames);
  1271. }
  1272. if (numNames == 0) {
  1273.     return GetSystemFont(display);
  1274. }
  1275.     }
  1276.     found:
  1277.     bestIdx[0] = -1;
  1278.     bestIdx[1] = -1;
  1279.     bestScore[0] = (unsigned int) -1;
  1280.     bestScore[1] = (unsigned int) -1;
  1281.     for (nameIdx = 0; nameIdx < numNames; nameIdx++) {
  1282. FontAttributes got;
  1283. int scalable;
  1284. unsigned int score;
  1285. if (TkFontParseXLFD(nameList[nameIdx], &got.fa, &got.xa) != TCL_OK) {
  1286.     continue;
  1287. }
  1288. IdentifySymbolEncodings(&got);
  1289. scalable = (got.fa.size == 0);
  1290. score = RankAttributes(&want, &got);
  1291. if (score < bestScore[scalable]) {
  1292.     bestIdx[scalable] = nameIdx;
  1293.     bestScore[scalable] = score;
  1294. }
  1295. if (score == 0) {
  1296.     break;
  1297. }
  1298.     }
  1299.     fontStructPtr = GetScreenFont(display, &want, nameList, bestIdx, bestScore);
  1300.     XFreeFontNames(nameList);
  1301.     
  1302.     if (fontStructPtr == NULL) {
  1303. return GetSystemFont(display);
  1304.     }
  1305.     return fontStructPtr;
  1306. }
  1307. /*
  1308.  *---------------------------------------------------------------------------
  1309.  *
  1310.  * InitFont --
  1311.  *
  1312.  * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().
  1313.  * Initializes the memory for a new UnixFont that  wraps the
  1314.  * platform-specific data.
  1315.  *
  1316.  * The caller is responsible for initializing the fields of the
  1317.  * TkFont that are used exclusively by the generic TkFont code, and
  1318.  * for releasing those fields before calling TkpDeleteFont().
  1319.  *
  1320.  * Results:
  1321.  * Fills the WinFont structure.
  1322.  *
  1323.  * Side effects:
  1324.  * Memory allocated.
  1325.  *
  1326.  *---------------------------------------------------------------------------
  1327.  */ 
  1328. static void
  1329. InitFont(tkwin, fontStructPtr, fontPtr)
  1330.     Tk_Window tkwin; /* For screen where font will be used. */
  1331.     XFontStruct *fontStructPtr; /* X information about font. */
  1332.     UnixFont *fontPtr; /* Filled with information constructed from
  1333.  * the above arguments. */
  1334. {
  1335.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  1336.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  1337.     unsigned long value;
  1338.     int minHi, maxHi, minLo, maxLo, fixed, width, limit, i, n;
  1339.     FontAttributes fa;
  1340.     TkFontAttributes *faPtr;
  1341.     TkFontMetrics *fmPtr;
  1342.     SubFont *controlPtr, *subFontPtr;
  1343.     char *pageMap;
  1344.     Display *display;
  1345.     /*
  1346.      * Get all font attributes and metrics.
  1347.      */
  1348.      
  1349.     display = Tk_Display(tkwin);
  1350.     GetFontAttributes(display, fontStructPtr, &fa);
  1351.     minHi = fontStructPtr->min_byte1;
  1352.     maxHi = fontStructPtr->max_byte1;
  1353.     minLo = fontStructPtr->min_char_or_byte2;
  1354.     maxLo = fontStructPtr->max_char_or_byte2;
  1355.     fixed = 1;
  1356.     if (fontStructPtr->per_char != NULL) {
  1357. width = 0;
  1358. limit = (maxHi - minHi + 1) * (maxLo - minLo + 1);
  1359. for (i = 0; i < limit; i++) {
  1360.     n = fontStructPtr->per_char[i].width;
  1361.     if (n != 0) {
  1362. if (width == 0) {
  1363.     width = n;
  1364. } else if (width != n) {
  1365.     fixed = 0;
  1366.     break;
  1367. }
  1368.     }
  1369. }
  1370.     }
  1371.     fontPtr->font.fid = fontStructPtr->fid;
  1372.     faPtr = &fontPtr->font.fa;
  1373.     faPtr->family = fa.fa.family;
  1374.     faPtr->size = TkFontGetPoints(tkwin, fa.fa.size);
  1375.     faPtr->weight = fa.fa.weight;
  1376.     faPtr->slant = fa.fa.slant;
  1377.     faPtr->underline = 0;
  1378.     faPtr->overstrike = 0;
  1379.     fmPtr = &fontPtr->font.fm;
  1380.     fmPtr->ascent = fontStructPtr->ascent;
  1381.     fmPtr->descent = fontStructPtr->descent;
  1382.     fmPtr->maxWidth = fontStructPtr->max_bounds.width;
  1383.     fmPtr->fixed = fixed;
  1384.     fontPtr->display = display;
  1385.     fontPtr->pixelSize = TkFontGetPixels(tkwin, fa.fa.size);
  1386.     fontPtr->xa = fa.xa;
  1387.     fontPtr->numSubFonts = 1;
  1388.     fontPtr->subFontArray = fontPtr->staticSubFonts;
  1389.     InitSubFont(display, fontStructPtr, 1, &fontPtr->subFontArray[0]);
  1390.     fontPtr->controlSubFont = fontPtr->subFontArray[0];
  1391.     subFontPtr = FindSubFontForChar(fontPtr, '0', NULL);
  1392.     controlPtr = &fontPtr->controlSubFont;
  1393.     controlPtr->fontStructPtr = subFontPtr->fontStructPtr;
  1394.     controlPtr->familyPtr = &tsdPtr->controlFamily;
  1395.     controlPtr->fontMap = tsdPtr->controlFamily.fontMap;
  1396.     
  1397.     pageMap = fontPtr->subFontArray[0].fontMap[0];
  1398.     for (i = 0; i < 256; i++) {
  1399. if ((minHi > 0) || (i < minLo) || (i > maxLo) ||
  1400. (((pageMap[i >> 3] >> (i & 7)) & 1) == 0)) {
  1401.     n = 0;
  1402. } else if (fontStructPtr->per_char == NULL) {
  1403.     n = fontStructPtr->max_bounds.width;
  1404. } else {
  1405.     n = fontStructPtr->per_char[i - minLo].width;
  1406. }
  1407. fontPtr->widths[i] = n;
  1408.     }
  1409.     
  1410.     if (XGetFontProperty(fontStructPtr, XA_UNDERLINE_POSITION, &value)) {
  1411. fontPtr->underlinePos = value;
  1412.     } else {
  1413. /*
  1414.  * If the XA_UNDERLINE_POSITION property does not exist, the X
  1415.  * manual recommends using the following value:
  1416.  */
  1417. fontPtr->underlinePos = fontStructPtr->descent / 2;
  1418.     }
  1419.     fontPtr->barHeight = 0;
  1420.     if (XGetFontProperty(fontStructPtr, XA_UNDERLINE_THICKNESS, &value)) {
  1421. fontPtr->barHeight = value;
  1422.     }
  1423.     if (fontPtr->barHeight == 0) {
  1424. /*
  1425.  * If the XA_UNDERLINE_THICKNESS property does not exist, the X
  1426.  * manual recommends using the width of the stem on a capital
  1427.  * letter.  I don't know of a way to get the stem width of a letter,
  1428.  * so guess and use 1/3 the width of a capital I.
  1429.  */
  1430. fontPtr->barHeight = fontPtr->widths['I'] / 3;
  1431. if (fontPtr->barHeight == 0) {
  1432.     fontPtr->barHeight = 1;
  1433. }
  1434.     }
  1435.     if (fontPtr->underlinePos + fontPtr->barHeight > fontStructPtr->descent) {
  1436. /*
  1437.  * If this set of cobbled together values would cause the bottom of
  1438.  * the underline bar to stick below the descent of the font, jack
  1439.  * the underline up a bit higher.
  1440.  */
  1441. fontPtr->barHeight = fontStructPtr->descent - fontPtr->underlinePos;
  1442. if (fontPtr->barHeight == 0) {
  1443.     fontPtr->underlinePos--;
  1444.     fontPtr->barHeight = 1;
  1445. }
  1446.     }
  1447. }
  1448. /*
  1449.  *-------------------------------------------------------------------------
  1450.  *
  1451.  * ReleaseFont --
  1452.  * 
  1453.  * Called to release the unix-specific contents of a TkFont.
  1454.  * The caller is responsible for freeing the memory used by the
  1455.  * font itself.
  1456.  *
  1457.  * Results:
  1458.  * None.
  1459.  *
  1460.  * Side effects:
  1461.  * Memory is freed.
  1462.  *
  1463.  *---------------------------------------------------------------------------
  1464.  */
  1465.  
  1466. static void
  1467. ReleaseFont(fontPtr)
  1468.     UnixFont *fontPtr; /* The font to delete. */
  1469. {
  1470.     int i;
  1471.     for (i = 0; i < fontPtr->numSubFonts; i++) {
  1472. ReleaseSubFont(fontPtr->display, &fontPtr->subFontArray[i]);
  1473.     }
  1474.     if (fontPtr->subFontArray != fontPtr->staticSubFonts) {
  1475. ckfree((char *) fontPtr->subFontArray);
  1476.     }
  1477. }
  1478. /*
  1479.  *-------------------------------------------------------------------------
  1480.  *
  1481.  * InitSubFont --
  1482.  *
  1483.  * Wrap a screen font and load the FontFamily that represents
  1484.  * it.  Used to prepare a SubFont so that characters can be mapped
  1485.  * from UTF-8 to the charset of the font.
  1486.  *
  1487.  * Results:
  1488.  * The subFontPtr is filled with information about the font.
  1489.  *
  1490.  * Side effects:
  1491.  * None.
  1492.  *
  1493.  *-------------------------------------------------------------------------
  1494.  */
  1495. static void
  1496. InitSubFont(display, fontStructPtr, base, subFontPtr)
  1497.     Display *display; /* Display in which font will be used. */
  1498.     XFontStruct *fontStructPtr; /* The screen font. */
  1499.     int base; /* Non-zero if this SubFont is being used
  1500.  * as the base font for a font object. */
  1501.     SubFont *subFontPtr; /* Filled with SubFont constructed from 
  1502.       * above attributes. */
  1503. {
  1504.     subFontPtr->fontStructPtr = fontStructPtr;
  1505.     subFontPtr->familyPtr   = AllocFontFamily(display, fontStructPtr, base);
  1506.     subFontPtr->fontMap     = subFontPtr->familyPtr->fontMap;
  1507. }
  1508. /*
  1509.  *-------------------------------------------------------------------------
  1510.  *
  1511.  * ReleaseSubFont --
  1512.  *
  1513.  * Called to release the contents of a SubFont.  The caller is 
  1514.  * responsible for freeing the memory used by the SubFont itself.
  1515.  *
  1516.  * Results:
  1517.  * None.
  1518.  *
  1519.  * Side effects:
  1520.  * Memory and resources are freed.
  1521.  *
  1522.  *---------------------------------------------------------------------------
  1523.  */
  1524. static void
  1525. ReleaseSubFont(display, subFontPtr)
  1526.     Display *display; /* Display which owns screen font. */
  1527.     SubFont *subFontPtr; /* The SubFont to delete. */
  1528. {
  1529.     XFreeFont(display, subFontPtr->fontStructPtr);
  1530.     FreeFontFamily(subFontPtr->familyPtr);
  1531. }
  1532. /*
  1533.  *-------------------------------------------------------------------------
  1534.  *
  1535.  * AllocFontFamily --
  1536.  *
  1537.  * Find the FontFamily structure associated with the given font
  1538.  * name.  The information should be stored by the caller in a 
  1539.  * SubFont and used when determining if that SubFont supports a 
  1540.  * character.
  1541.  *
  1542.  * Cannot use the string name used to construct the font as the 
  1543.  * key, because the capitalization may not be canonical.  Therefore
  1544.  * use the face name actually retrieved from the font metrics as
  1545.  * the key.
  1546.  *
  1547.  * Results:
  1548.  * A pointer to a FontFamily.  The reference count in the FontFamily
  1549.  * is automatically incremented.  When the SubFont is released, the
  1550.  * reference count is decremented.  When no SubFont is using this
  1551.  * FontFamily, it may be deleted.
  1552.  *
  1553.  * Side effects:
  1554.  * A new FontFamily structure will be allocated if this font family
  1555.  * has not been seen.  TrueType character existence metrics are
  1556.  * loaded into the FontFamily structure.
  1557.  *
  1558.  *-------------------------------------------------------------------------
  1559.  */
  1560. static FontFamily *
  1561. AllocFontFamily(display, fontStructPtr, base)
  1562.     Display *display; /* Display in which font will be used. */
  1563.     XFontStruct *fontStructPtr; /* Screen font whose FontFamily is to be
  1564.  * returned. */
  1565.     int base; /* Non-zero if this font family is to be
  1566.  * used in the base font of a font object. */
  1567. {
  1568.     FontFamily *familyPtr;
  1569.     FontAttributes fa;
  1570.     Tcl_Encoding encoding;
  1571.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  1572.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  1573.     GetFontAttributes(display, fontStructPtr, &fa);
  1574.     encoding = Tcl_GetEncoding(NULL, GetEncodingAlias(fa.xa.charset));
  1575.     familyPtr = tsdPtr->fontFamilyList;
  1576.     for (; familyPtr != NULL; familyPtr = familyPtr->nextPtr) {
  1577. if ((familyPtr->faceName == fa.fa.family)
  1578. && (familyPtr->foundry == fa.xa.foundry)
  1579. && (familyPtr->encoding == encoding)) {
  1580.     Tcl_FreeEncoding(encoding);
  1581.     familyPtr->refCount++;
  1582.     return familyPtr;
  1583. }
  1584.     }
  1585.     familyPtr = (FontFamily *) ckalloc(sizeof(FontFamily));
  1586.     memset(familyPtr, 0, sizeof(FontFamily));
  1587.     familyPtr->nextPtr = tsdPtr->fontFamilyList;
  1588.     tsdPtr->fontFamilyList = familyPtr;
  1589.     /* 
  1590.      * Set key for this FontFamily. 
  1591.      */
  1592.      
  1593.     familyPtr->foundry = fa.xa.foundry;
  1594.     familyPtr->faceName = fa.fa.family;
  1595.     familyPtr->encoding = encoding;
  1596.     /* 
  1597.      * An initial refCount of 2 means that FontFamily information will
  1598.      * persist even when the SubFont that loaded the FontFamily is released.
  1599.      * Change it to 1 to cause FontFamilies to be unloaded when not in use.
  1600.      */
  1601.     familyPtr->refCount = 2;
  1602.     /*
  1603.      * One byte/character fonts have both min_byte1 and max_byte1 0,
  1604.      * and max_char_or_byte2 <= 255.
  1605.      * Anything else specifies a two byte/character font.
  1606.      */
  1607.     familyPtr->isTwoByteFont = !(
  1608.     (fontStructPtr->min_byte1 == 0) &&
  1609.     (fontStructPtr->max_byte1 == 0) &&
  1610.     (fontStructPtr->max_char_or_byte2 < 256));
  1611.     return familyPtr;
  1612. }
  1613. /*
  1614.  *-------------------------------------------------------------------------
  1615.  *
  1616.  * FreeFontFamily --
  1617.  *
  1618.  * Called to free an FontFamily when the SubFont is finished using
  1619.  * it. Frees the contents of the FontFamily and the memory used by
  1620.  * the FontFamily itself.
  1621.  *
  1622.  * Results:
  1623.  * None.
  1624.  *
  1625.  * Side effects:
  1626.  * None.
  1627.  *
  1628.  *-------------------------------------------------------------------------
  1629.  */
  1630.  
  1631. static void
  1632. FreeFontFamily(familyPtr)
  1633.     FontFamily *familyPtr; /* The FontFamily to delete. */
  1634. {
  1635.     FontFamily **familyPtrPtr;
  1636.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  1637.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  1638.     int i;
  1639.     if (familyPtr == NULL) {
  1640.         return;
  1641.     }
  1642.     familyPtr->refCount--;
  1643.     if (familyPtr->refCount > 0) {
  1644.      return;
  1645.     }
  1646.     Tcl_FreeEncoding(familyPtr->encoding);
  1647.     for (i = 0; i < FONTMAP_PAGES; i++) {
  1648.         if (familyPtr->fontMap[i] != NULL) {
  1649.             ckfree(familyPtr->fontMap[i]);
  1650.         }
  1651.     }
  1652.     
  1653.     /* 
  1654.      * Delete from list. 
  1655.      */
  1656.          
  1657.     for (familyPtrPtr = &tsdPtr->fontFamilyList; ; ) {
  1658.         if (*familyPtrPtr == familyPtr) {
  1659.        *familyPtrPtr = familyPtr->nextPtr;
  1660.     break;
  1661. }
  1662. familyPtrPtr = &(*familyPtrPtr)->nextPtr;
  1663.     }
  1664.     
  1665.     ckfree((char *) familyPtr);
  1666. }
  1667. /*
  1668.  *-------------------------------------------------------------------------
  1669.  *
  1670.  * FindSubFontForChar --
  1671.  *
  1672.  * Determine which screen font is necessary to use to 
  1673.  * display the given character.  If the font object does not have
  1674.  * a screen font that can display the character, another screen font
  1675.  * may be loaded into the font object, following a set of preferred
  1676.  * fallback rules.
  1677.  *
  1678.  * Results:
  1679.  * The return value is the SubFont to use to display the given 
  1680.  * character. 
  1681.  *
  1682.  * Side effects:
  1683.  * The contents of fontPtr are modified to cache the results
  1684.  * of the lookup and remember any SubFonts that were dynamically 
  1685.  * loaded.  The table of SubFonts might be extended, and if a non-NULL
  1686.  * reference to a subfont pointer is available, it is updated if it
  1687.  * previously pointed into the old subfont table.
  1688.  *
  1689.  *-------------------------------------------------------------------------
  1690.  */
  1691. static SubFont *
  1692. FindSubFontForChar(fontPtr, ch, fixSubFontPtrPtr)
  1693.     UnixFont *fontPtr; /* The font object with which the character
  1694.  * will be displayed. */
  1695.     int ch; /* The Unicode character to be displayed. */
  1696.     SubFont **fixSubFontPtrPtr; /* Subfont reference to fix up if we
  1697.  * reallocate our subfont table. */
  1698. {
  1699.     int i, j, k, numNames;
  1700.     Tk_Uid faceName; 
  1701.     char *fallback;
  1702.     char **aliases, **nameList, **anyFallbacks;
  1703.     char ***fontFallbacks;
  1704.     SubFont *subFontPtr;
  1705.     Tcl_DString ds;
  1706.     if (FontMapLookup(&fontPtr->subFontArray[0], ch)) {
  1707. return &fontPtr->subFontArray[0];
  1708.     }
  1709.     for (i = 1; i < fontPtr->numSubFonts; i++) {
  1710. if (FontMapLookup(&fontPtr->subFontArray[i], ch)) {
  1711.     return &fontPtr->subFontArray[i];
  1712. }
  1713.     }
  1714.     if (FontMapLookup(&fontPtr->controlSubFont, ch)) {
  1715. return &fontPtr->controlSubFont;
  1716.     }
  1717.     /*
  1718.      * Keep track of all face names that we check, so we don't check some
  1719.      * name multiple times if it can be reached by multiple paths.
  1720.      */
  1721.      
  1722.     Tcl_DStringInit(&ds);
  1723.     /*
  1724.      * Are there any other fonts with the same face name as the base
  1725.      * font that could display this character, e.g., if the base font
  1726.      * is adobe:fixed:iso8859-1, we could might be able to use
  1727.      * misc:fixed:iso8859-8 or sony:fixed:jisx0208.1983-0
  1728.      */
  1729.      
  1730.     faceName = fontPtr->font.fa.family;
  1731.     if (SeenName(faceName, &ds) == 0) {
  1732. subFontPtr = CanUseFallback(fontPtr, faceName, ch, fixSubFontPtrPtr);
  1733. if (subFontPtr != NULL) {
  1734.     goto end;
  1735. }
  1736.     }
  1737.     aliases = TkFontGetAliasList(faceName);
  1738.     subFontPtr = NULL;
  1739.     fontFallbacks = TkFontGetFallbacks();
  1740.     for (i = 0; fontFallbacks[i] != NULL; i++) {
  1741. for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {
  1742.     if (strcasecmp(fallback, faceName) == 0) {
  1743. /*
  1744.  * If the base font has a fallback...
  1745.  */
  1746. goto tryfallbacks;
  1747.     } else if (aliases != NULL) {
  1748. /* 
  1749.  * Or if an alias for the base font has a fallback...
  1750.  */
  1751. for (k = 0; aliases[k] != NULL; k++) {
  1752.     if (strcasecmp(fallback, aliases[k]) == 0) {
  1753. goto tryfallbacks;
  1754.     }
  1755. }
  1756.     }
  1757. }
  1758. continue;
  1759. tryfallbacks:
  1760. /* 
  1761.  * ...then see if we can use one of the fallbacks, or an
  1762.  * alias for one of the fallbacks.
  1763.  */
  1764. for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {
  1765.     subFontPtr = CanUseFallbackWithAliases(fontPtr, fallback, ch, &ds,
  1766.     fixSubFontPtrPtr);
  1767.     if (subFontPtr != NULL) {
  1768. goto end;
  1769.     }
  1770. }
  1771.     }
  1772.     /*
  1773.      * See if we can use something from the global fallback list. 
  1774.      */
  1775.     anyFallbacks = TkFontGetGlobalClass();
  1776.     for (i = 0; (fallback = anyFallbacks[i]) != NULL; i++) {
  1777. subFontPtr = CanUseFallbackWithAliases(fontPtr, fallback, ch, &ds,
  1778. fixSubFontPtrPtr);
  1779. if (subFontPtr != NULL) {
  1780.     goto end;
  1781. }
  1782.     }
  1783.     /*
  1784.      * Try all face names available in the whole system until we
  1785.      * find one that can be used.
  1786.      */
  1787.     nameList = ListFonts(fontPtr->display, "*", &numNames);
  1788.     for (i = 0; i < numNames; i++) {
  1789. fallback = strchr(nameList[i] + 1, '-') + 1;
  1790. strchr(fallback, '-')[0] = '';
  1791. if (SeenName(fallback, &ds) == 0) {
  1792.     subFontPtr = CanUseFallback(fontPtr, fallback, ch,
  1793.     fixSubFontPtrPtr);
  1794.     if (subFontPtr != NULL) {
  1795. XFreeFontNames(nameList);
  1796. goto end;
  1797.     }
  1798. }
  1799.     }
  1800.     XFreeFontNames(nameList);
  1801.     end:
  1802.     Tcl_DStringFree(&ds);
  1803.     if (subFontPtr == NULL) {
  1804. /*
  1805.  * No font can display this character, so it will be displayed as a
  1806.  * control character expansion.
  1807.  */
  1808. subFontPtr = &fontPtr->controlSubFont;
  1809. FontMapInsert(subFontPtr, ch);
  1810.     }
  1811.     return subFontPtr;
  1812. }
  1813. /*
  1814.  *-------------------------------------------------------------------------
  1815.  *
  1816.  * FontMapLookup --
  1817.  *
  1818.  * See if the screen font can display the given character.
  1819.  *
  1820.  * Results:
  1821.  * The return value is 0 if the screen font cannot display the
  1822.  * character, non-zero otherwise.
  1823.  *
  1824.  * Side effects:
  1825.  * New pages are added to the font mapping cache whenever the
  1826.  * character belongs to a page that hasn't been seen before.
  1827.  * When a page is loaded, information about all the characters on
  1828.  * that page is stored, not just for the single character in
  1829.  * question.
  1830.  *
  1831.  *-------------------------------------------------------------------------
  1832.  */
  1833. static int
  1834. FontMapLookup(subFontPtr, ch)
  1835.     SubFont *subFontPtr; /* Contains font mapping cache to be queried
  1836.  * and possibly updated. */
  1837.     int ch; /* Character to be tested. */
  1838. {
  1839.     int row, bitOffset;
  1840.     row = ch >> FONTMAP_SHIFT;
  1841.     if (subFontPtr->fontMap[row] == NULL) {
  1842. FontMapLoadPage(subFontPtr, row);
  1843.     }
  1844.     bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);
  1845.     return (subFontPtr->fontMap[row][bitOffset >> 3] >> (bitOffset & 7)) & 1;
  1846. }
  1847. /*
  1848.  *-------------------------------------------------------------------------
  1849.  *
  1850.  * FontMapInsert --
  1851.  *
  1852.  * Tell the font mapping cache that the given screen font should be
  1853.  * used to display the specified character.  This is called when no
  1854.  * font on the system can be be found that can display that 
  1855.  * character; we lie to the font and tell it that it can display
  1856.  * the character, otherwise we would end up re-searching the entire
  1857.  * fallback hierarchy every time that character was seen.
  1858.  *
  1859.  * Results:
  1860.  * None.
  1861.  *
  1862.  * Side effects:
  1863.  * New pages are added to the font mapping cache whenever the
  1864.  * character belongs to a page that hasn't been seen before.
  1865.  * When a page is loaded, information about all the characters on
  1866.  * that page is stored, not just for the single character in
  1867.  * question.
  1868.  *
  1869.  *-------------------------------------------------------------------------
  1870.  */
  1871. static void
  1872. FontMapInsert(subFontPtr, ch)
  1873.     SubFont *subFontPtr; /* Contains font mapping cache to be 
  1874.  * updated. */
  1875.     int ch; /* Character to be added to cache. */
  1876. {
  1877.     int row, bitOffset;
  1878.     row = ch >> FONTMAP_SHIFT;
  1879.     if (subFontPtr->fontMap[row] == NULL) {
  1880. FontMapLoadPage(subFontPtr, row);
  1881.     }
  1882.     bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);
  1883.     subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);
  1884. }
  1885. /*
  1886.  *-------------------------------------------------------------------------
  1887.  *
  1888.  * FontMapLoadPage --
  1889.  *
  1890.  * Load information about all the characters on a given page.
  1891.  * This information consists of one bit per character that indicates
  1892.  * whether the associated screen font can (1) or cannot (0) display
  1893.  * the characters on the page.
  1894.  *
  1895.  * Results:
  1896.  * None.
  1897.  *
  1898.  * Side effects:
  1899.  * Mempry allocated.
  1900.  *
  1901.  *-------------------------------------------------------------------------
  1902.  */
  1903. static void 
  1904. FontMapLoadPage(subFontPtr, row)
  1905.     SubFont *subFontPtr; /* Contains font mapping cache to be 
  1906.  * updated. */
  1907.     int row; /* Index of the page to be loaded into 
  1908.  * the cache. */
  1909. {
  1910.     char buf[16], src[TCL_UTF_MAX];
  1911.     int minHi, maxHi, minLo, maxLo, scale, checkLo;
  1912.     int i, end, bitOffset, isTwoByteFont, n;
  1913.     Tcl_Encoding encoding;
  1914.     XFontStruct *fontStructPtr;
  1915.     XCharStruct *widths;
  1916.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  1917.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  1918.     subFontPtr->fontMap[row] = (char *) ckalloc(FONTMAP_BITSPERPAGE / 8);
  1919.     memset(subFontPtr->fontMap[row], 0, FONTMAP_BITSPERPAGE / 8);
  1920.     if (subFontPtr->familyPtr == &tsdPtr->controlFamily) {
  1921. return;
  1922.     }
  1923.     fontStructPtr   = subFontPtr->fontStructPtr;
  1924.     encoding     = subFontPtr->familyPtr->encoding;
  1925.     isTwoByteFont   = subFontPtr->familyPtr->isTwoByteFont;
  1926.     widths = fontStructPtr->per_char;
  1927.     minHi = fontStructPtr->min_byte1;
  1928.     maxHi = fontStructPtr->max_byte1;
  1929.     minLo = fontStructPtr->min_char_or_byte2;
  1930.     maxLo = fontStructPtr->max_char_or_byte2;
  1931.     scale = maxLo - minLo + 1;
  1932.     checkLo = minLo;
  1933.     if (! isTwoByteFont) {
  1934. if (minLo < 32) {
  1935.     checkLo = 32;
  1936. }
  1937.     }
  1938.     end = (row + 1) << FONTMAP_SHIFT;
  1939.     for (i = row << FONTMAP_SHIFT; i < end; i++) {
  1940. int hi, lo;
  1941. if (Tcl_UtfToExternal(NULL, encoding, src, Tcl_UniCharToUtf(i, src),
  1942.          TCL_ENCODING_STOPONERROR, NULL, buf, sizeof(buf), NULL, 
  1943. NULL, NULL) != TCL_OK) {
  1944.     continue;
  1945. }
  1946. if (isTwoByteFont) {
  1947.     hi = ((unsigned char *) buf)[0];
  1948.     lo = ((unsigned char *) buf)[1];
  1949. } else {
  1950.     hi = 0;
  1951.     lo = ((unsigned char *) buf)[0];
  1952. }
  1953. if ((hi < minHi) || (hi > maxHi) || (lo < checkLo) || (lo > maxLo)) {
  1954.     continue;
  1955. }
  1956. n = (hi - minHi) * scale + lo - minLo;
  1957. if ((widths == NULL) || ((widths[n].width + widths[n].rbearing) != 0)) {
  1958.     bitOffset = i & (FONTMAP_BITSPERPAGE - 1);
  1959.     subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);
  1960. }
  1961.     }
  1962. }
  1963. /*
  1964.  *---------------------------------------------------------------------------
  1965.  *
  1966.  * CanUseFallbackWithAliases --
  1967.  *
  1968.  * Helper function for FindSubFontForChar.  Determine if the
  1969.  * specified face name (or an alias of the specified face name)
  1970.  * can be used to construct a screen font that can display the
  1971.  * given character.
  1972.  *
  1973.  * Results:
  1974.  * See CanUseFallback().
  1975.  *
  1976.  * Side effects:
  1977.  * If the name and/or one of its aliases was rejected, the
  1978.  * rejected string is recorded in nameTriedPtr so that it won't
  1979.  * be tried again.  The table of SubFonts might be extended, and if
  1980.  * a non-NULL reference to a subfont pointer is available, it is
  1981.  * updated if it previously pointed into the old subfont table.
  1982.  *
  1983.  *---------------------------------------------------------------------------
  1984.  */
  1985. static SubFont *
  1986. CanUseFallbackWithAliases(fontPtr, faceName, ch, nameTriedPtr,
  1987. fixSubFontPtrPtr)
  1988.     UnixFont *fontPtr; /* The font object that will own the new
  1989.  * screen font. */
  1990.     char *faceName; /* Desired face name for new screen font. */
  1991.     int ch; /* The Unicode character that the new
  1992.  * screen font must be able to display. */
  1993.     Tcl_DString *nameTriedPtr; /* Records face names that have already
  1994.  * been tried.  It is possible for the same
  1995.  * face name to be queried multiple times when
  1996.  * trying to find a suitable screen font. */
  1997.     SubFont **fixSubFontPtrPtr; /* Subfont reference to fix up if we
  1998.  * reallocate our subfont table. */
  1999. {
  2000.     SubFont *subFontPtr;
  2001.     char **aliases;
  2002.     int i;
  2003.     
  2004.     if (SeenName(faceName, nameTriedPtr) == 0) {
  2005. subFontPtr = CanUseFallback(fontPtr, faceName, ch, fixSubFontPtrPtr);
  2006. if (subFontPtr != NULL) {
  2007.     return subFontPtr;
  2008. }
  2009.     }
  2010.     aliases = TkFontGetAliasList(faceName);
  2011.     if (aliases != NULL) {
  2012. for (i = 0; aliases[i] != NULL; i++) {
  2013.     if (SeenName(aliases[i], nameTriedPtr) == 0) {
  2014. subFontPtr = CanUseFallback(fontPtr, aliases[i], ch,
  2015. fixSubFontPtrPtr);
  2016. if (subFontPtr != NULL) {
  2017.     return subFontPtr;
  2018. }
  2019.     }
  2020. }
  2021.     }
  2022.     return NULL;
  2023. }
  2024. /*
  2025.  *---------------------------------------------------------------------------
  2026.  *
  2027.  * SeenName --
  2028.  *
  2029.  * Used to determine we have already tried and rejected the given
  2030.  * face name when looking for a screen font that can support some
  2031.  * Unicode character.
  2032.  *
  2033.  * Results:
  2034.  * The return value is 0 if this face name has not already been seen,
  2035.  * non-zero otherwise.
  2036.  *
  2037.  * Side effects:
  2038.  * None.
  2039.  *
  2040.  *---------------------------------------------------------------------------
  2041.  */
  2042. static int
  2043. SeenName(name, dsPtr)
  2044.     CONST char *name; /* The name to check. */
  2045.     Tcl_DString *dsPtr; /* Contains names that have already been
  2046.  * seen. */
  2047. {
  2048.     CONST char *seen, *end;
  2049.     seen = Tcl_DStringValue(dsPtr);
  2050.     end = seen + Tcl_DStringLength(dsPtr);
  2051.     while (seen < end) {
  2052. if (strcasecmp(seen, name) == 0) {
  2053.     return 1;
  2054. }
  2055. seen += strlen(seen) + 1;
  2056.     }
  2057.     Tcl_DStringAppend(dsPtr, (char *) name, (int) (strlen(name) + 1));
  2058.     return 0;
  2059. }
  2060. /*
  2061.  *-------------------------------------------------------------------------
  2062.  *
  2063.  * CanUseFallback --
  2064.  *
  2065.  * If the specified screen font has not already been loaded 
  2066.  * into the font object, determine if the specified screen 
  2067.  * font can display the given character.
  2068.  *
  2069.  * Results:
  2070.  * The return value is a pointer to a newly allocated SubFont,
  2071.  * owned by the font object.  This SubFont can be used to display
  2072.  * the given character.  The SubFont represents the screen font
  2073.  * with the base set of font attributes from the font object, but
  2074.  * using the specified face name.  NULL is returned if the font
  2075.  * object already holds a reference to the specified font or if
  2076.  * the specified font doesn't exist or cannot display the given
  2077.  * character.
  2078.  *
  2079.  * Side effects:        
  2080.  * The font object's subFontArray is updated to contain a reference
  2081.  * to the newly allocated SubFont.  The table of SubFonts might be
  2082.  * extended, and if a non-NULL reference to a subfont pointer is
  2083.  * available, it is updated if it previously pointed into the old
  2084.  * subfont table.
  2085.  *
  2086.  *-------------------------------------------------------------------------
  2087.  */
  2088. static SubFont *
  2089. CanUseFallback(fontPtr, faceName, ch, fixSubFontPtrPtr)
  2090.     UnixFont *fontPtr; /* The font object that will own the new
  2091.  * screen font. */
  2092.     CONST char *faceName; /* Desired face name for new screen font. */
  2093.     int ch; /* The Unicode character that the new
  2094.  * screen font must be able to display. */
  2095.     SubFont **fixSubFontPtrPtr; /* Subfont reference to fix up if we
  2096.  * reallocate our subfont table. */
  2097. {
  2098.     int i, nameIdx, numNames, srcLen;
  2099.     Tk_Uid hateFoundry;
  2100.     int bestIdx[2];
  2101.     CONST char *charset, *hateCharset;
  2102.     unsigned int bestScore[2];
  2103.     char **nameList, **nameListOrig;
  2104.     FontAttributes want, got;
  2105.     char src[TCL_UTF_MAX];
  2106.     Display *display;
  2107.     SubFont subFont;
  2108.     XFontStruct *fontStructPtr;
  2109.     Tcl_DString dsEncodings;
  2110.     int numEncodings;
  2111.     Tcl_Encoding *encodingCachePtr;
  2112.     /*
  2113.      * Assume: the face name is times.
  2114.      * Assume: adobe:times:iso8859-1 has already been used.
  2115.      *
  2116.      * Are there any versions of times that can display this
  2117.      *    character (e.g., perhaps linotype:times:iso8859-2)?
  2118.      *   a. Get list of all times fonts.
  2119.      *   b1. Cross out all names whose encodings we've already used.
  2120.      *   b2. Cross out all names whose foundry & encoding we've already seen.
  2121.      *   c. Cross out all names whose encoding cannot handle the character.
  2122.      *   d. Rank each name and pick the best match.
  2123.      *   e. If that font cannot actually display the character, cross
  2124.      *      out all names with the same foundry and encoding and go
  2125.      *      back to (c).
  2126.      */
  2127.     display = fontPtr->display;
  2128.     nameList = ListFonts(display, faceName, &numNames);
  2129.     if (numNames == 0) {
  2130. return NULL;
  2131.     }
  2132.     nameListOrig = nameList;
  2133.     srcLen = Tcl_UniCharToUtf(ch, src);
  2134.     want.fa = fontPtr->font.fa;
  2135.     want.xa = fontPtr->xa;
  2136.     want.fa.family = Tk_GetUid(faceName);
  2137.     want.fa.size = -fontPtr->pixelSize;
  2138.     hateFoundry = NULL;
  2139.     hateCharset = NULL;
  2140.     numEncodings = 0;
  2141.     Tcl_DStringInit(&dsEncodings);
  2142.     charset = NULL; /* lint, since numNames must be > 0 to get here. */
  2143.     retry:
  2144.     bestIdx[0] = -1;
  2145.     bestIdx[1] = -1;
  2146.     bestScore[0] = (unsigned int) -1;
  2147.     bestScore[1] = (unsigned int) -1;
  2148.     for (nameIdx = 0; nameIdx < numNames; nameIdx++) {
  2149. Tcl_Encoding encoding;
  2150. char dst[16];
  2151. int scalable, srcRead, dstWrote;
  2152. unsigned int score;
  2153. if (nameList[nameIdx] == NULL) {
  2154.     continue;
  2155. }
  2156. if (TkFontParseXLFD(nameList[nameIdx], &got.fa, &got.xa) != TCL_OK) {
  2157.     goto crossout;
  2158. }
  2159. IdentifySymbolEncodings(&got);
  2160. charset = GetEncodingAlias(got.xa.charset);
  2161. if (hateFoundry != NULL) {
  2162.     /*
  2163.      * E. If the font we picked cannot actually display the
  2164.      * character, cross out all names with the same foundry and
  2165.      * encoding. 
  2166.      */
  2167.     if ((hateFoundry == got.xa.foundry)
  2168.     && (strcmp(hateCharset, charset) == 0)) {
  2169. goto crossout;
  2170.     }
  2171. } else {
  2172.     /*
  2173.      * B. Cross out all names whose encodings we've already used.
  2174.      */
  2175.      
  2176.     for (i = 0; i < fontPtr->numSubFonts; i++) {
  2177. encoding = fontPtr->subFontArray[i].familyPtr->encoding;
  2178. if (strcmp(charset, Tcl_GetEncodingName(encoding)) == 0) {
  2179.     goto crossout;
  2180. }
  2181.     }
  2182. }
  2183. /*
  2184.  * C. Cross out all names whose encoding cannot handle the character.
  2185.  */
  2186.  
  2187. encodingCachePtr = (Tcl_Encoding *) Tcl_DStringValue(&dsEncodings);
  2188. for (i = numEncodings; --i >= 0; encodingCachePtr++) {
  2189.     encoding = *encodingCachePtr;
  2190.     if (strcmp(Tcl_GetEncodingName(encoding), charset) == 0) {
  2191. break;
  2192.     }
  2193. }
  2194. if (i < 0) {
  2195.     encoding = Tcl_GetEncoding(NULL, charset);
  2196.     if (encoding == NULL) {
  2197. goto crossout;
  2198.     }
  2199.     Tcl_DStringAppend(&dsEncodings, (char *) &encoding,
  2200.     sizeof(encoding));
  2201.     numEncodings++;
  2202. }
  2203. Tcl_UtfToExternal(NULL, encoding, src, srcLen, 
  2204. TCL_ENCODING_STOPONERROR, NULL, dst, sizeof(dst), &srcRead, 
  2205. &dstWrote, NULL);
  2206. if (dstWrote == 0) {
  2207.     goto crossout;
  2208. }
  2209. /*
  2210.  * D. Rank each name and pick the best match.
  2211.  */
  2212. scalable = (got.fa.size == 0);
  2213. score = RankAttributes(&want, &got);
  2214. if (score < bestScore[scalable]) {
  2215.     bestIdx[scalable] = nameIdx;
  2216.     bestScore[scalable] = score;
  2217. }
  2218. if (score == 0) {
  2219.     break;
  2220. }
  2221. continue;
  2222. crossout:
  2223. if (nameList == nameListOrig) {
  2224.     /*
  2225.      * Not allowed to change pointers to memory that X gives you,
  2226.      * so make a copy.
  2227.      */
  2228.     nameList = (char **) ckalloc(numNames * sizeof(char *));
  2229.     memcpy(nameList, nameListOrig, numNames * sizeof(char *));
  2230. }
  2231. nameList[nameIdx] = NULL;
  2232.     }
  2233.     fontStructPtr = GetScreenFont(display, &want, nameList, bestIdx, bestScore);
  2234.     encodingCachePtr = (Tcl_Encoding *) Tcl_DStringValue(&dsEncodings);
  2235.     for (i = numEncodings; --i >= 0; encodingCachePtr++) {
  2236. Tcl_FreeEncoding(*encodingCachePtr);
  2237.     }
  2238.     Tcl_DStringFree(&dsEncodings);
  2239.     numEncodings = 0;
  2240.     if (fontStructPtr == NULL) {
  2241. if (nameList != nameListOrig) {
  2242.     ckfree((char *) nameList);
  2243. }
  2244. XFreeFontNames(nameListOrig);
  2245. return NULL;
  2246.     }
  2247.     InitSubFont(display, fontStructPtr, 0, &subFont);
  2248.     if (FontMapLookup(&subFont, ch) == 0) {
  2249. /*
  2250.  * E. If the font we picked cannot actually display the character,
  2251.  * cross out all names with the same foundry and encoding and pick
  2252.  * another font.
  2253.  */
  2254. hateFoundry = got.xa.foundry;
  2255. hateCharset = charset;
  2256. ReleaseSubFont(display, &subFont);
  2257. goto retry;
  2258.     }
  2259.     if (nameList != nameListOrig) {
  2260. ckfree((char *) nameList);
  2261.     }
  2262.     XFreeFontNames(nameListOrig);
  2263.     if (fontPtr->numSubFonts >= SUBFONT_SPACE) {
  2264. SubFont *newPtr;
  2265. newPtr = (SubFont *) ckalloc(sizeof(SubFont) * (fontPtr->numSubFonts + 1));
  2266. memcpy((char *) newPtr, fontPtr->subFontArray,
  2267. fontPtr->numSubFonts * sizeof(SubFont));
  2268. if (fixSubFontPtrPtr != NULL) {
  2269.     register SubFont *fixSubFontPtr = *fixSubFontPtrPtr;
  2270.     if (fixSubFontPtr != &fontPtr->controlSubFont) {
  2271. *fixSubFontPtrPtr =
  2272. newPtr + (fixSubFontPtr - fontPtr->subFontArray);
  2273.     }
  2274. }
  2275. if (fontPtr->subFontArray != fontPtr->staticSubFonts) {
  2276.     ckfree((char *) fontPtr->subFontArray);
  2277. }
  2278. fontPtr->subFontArray = newPtr;
  2279.     }
  2280.     fontPtr->subFontArray[fontPtr->numSubFonts] = subFont;
  2281.     fontPtr->numSubFonts++;
  2282.     return &fontPtr->subFontArray[fontPtr->numSubFonts - 1];
  2283. }
  2284. /*
  2285.  *---------------------------------------------------------------------------
  2286.  *
  2287.  * RankAttributes --
  2288.  *
  2289.  * Determine how close the attributes of the font in question match
  2290.  * the attributes that we want.
  2291.  *
  2292.  * Results:
  2293.  * The return value is the score; lower numbers are better.
  2294.  * *scalablePtr is set to 0 if the font was not scalable, 1 otherwise.
  2295.  *
  2296.  * Side effects:
  2297.  * None.
  2298.  *
  2299.  *---------------------------------------------------------------------------
  2300.  */
  2301. static unsigned int
  2302. RankAttributes(wantPtr, gotPtr)
  2303.     FontAttributes *wantPtr; /* The desired attributes. */
  2304.     FontAttributes *gotPtr; /* The attributes we have to live with. */
  2305. {
  2306.     unsigned int penalty;
  2307.     penalty = 0;
  2308.     if (gotPtr->xa.foundry != wantPtr->xa.foundry) {
  2309. penalty += 4500;
  2310.     }
  2311.     if (gotPtr->fa.family != wantPtr->fa.family) {
  2312. penalty += 9000;
  2313.     }
  2314.     if (gotPtr->fa.weight != wantPtr->fa.weight) {
  2315. penalty += 90;
  2316.     }
  2317.     if (gotPtr->fa.slant != wantPtr->fa.slant) {
  2318. penalty += 60;
  2319.     }
  2320.     if (gotPtr->xa.slant != wantPtr->xa.slant) {
  2321. penalty += 10;
  2322.     }
  2323.     if (gotPtr->xa.setwidth != wantPtr->xa.setwidth) {
  2324. penalty += 1000;
  2325.     }
  2326.     if (gotPtr->fa.size == 0) {
  2327. /*
  2328.  * A scalable font is almost always acceptable, but the
  2329.  * corresponding bitmapped font would be better.
  2330.  */
  2331. penalty += 10;
  2332.     } else {
  2333. int diff;
  2334. /*
  2335.  * It's worse to be too large than to be too small.
  2336.  */
  2337.  
  2338. diff = (-gotPtr->fa.size - -wantPtr->fa.size);
  2339. if (diff > 0) {
  2340.     penalty += 600;
  2341. } else if (diff < 0) {
  2342.     penalty += 150;
  2343.     diff = -diff;
  2344. }
  2345. penalty += 150 * diff;
  2346.     }
  2347.     if (gotPtr->xa.charset != wantPtr->xa.charset) {
  2348. int i;
  2349. CONST char *gotAlias, *wantAlias;
  2350. penalty += 65000;
  2351. gotAlias = GetEncodingAlias(gotPtr->xa.charset);
  2352. wantAlias = GetEncodingAlias(wantPtr->xa.charset); 
  2353. if (strcmp(gotAlias, wantAlias) != 0) {
  2354.     penalty += 30000;
  2355.     for (i = 0; encodingList[i] != NULL; i++) {
  2356. if (strcmp(gotAlias, encodingList[i]) == 0) {
  2357.     penalty -= 30000;
  2358.     break;
  2359. }
  2360. penalty += 20000;
  2361.     }
  2362. }
  2363.     }
  2364.     return penalty;
  2365. }
  2366. /*
  2367.  *---------------------------------------------------------------------------
  2368.  *
  2369.  * GetScreenFont --
  2370.  *
  2371.  * Given the names for the best scalable and best bitmapped font,
  2372.  * actually construct an XFontStruct based on the best XLFD.
  2373.  * This is where all the alias and fallback substitution bottoms
  2374.  * out.
  2375.  *
  2376.  * Results:
  2377.  * The screen font that best corresponds to the set of attributes.
  2378.  *
  2379.  * Side effects:
  2380.  * None.
  2381.  *
  2382.  *---------------------------------------------------------------------------
  2383.  */
  2384. static XFontStruct *
  2385. GetScreenFont(display, wantPtr, nameList, bestIdx, bestScore)
  2386.     Display *display; /* Display for new XFontStruct. */
  2387.     FontAttributes *wantPtr; /* Contains desired actual pixel-size if the
  2388.  * best font was scalable. */
  2389.     char **nameList; /* Array of XLFDs. */
  2390.     int bestIdx[2]; /* Indices into above array for XLFD of
  2391.  * best bitmapped and best scalable font. */
  2392.     unsigned int bestScore[2]; /* Scores of best bitmapped and best
  2393.  * scalable font.  XLFD corresponding to
  2394.  * lowest score will be constructed. */
  2395. {
  2396.     XFontStruct *fontStructPtr;
  2397.     if ((bestIdx[0] < 0) && (bestIdx[1] < 0)) {
  2398. return NULL;
  2399.     }
  2400.     /*
  2401.      * Now we know which is the closest matching scalable font and the
  2402.      * closest matching bitmapped font.  If the scalable font was a
  2403.      * better match, try getting the scalable font; however, if the
  2404.      * scalable font was not actually available in the desired
  2405.      * pointsize, fall back to the closest bitmapped font.
  2406.      */
  2407.     fontStructPtr = NULL;
  2408.     if (bestScore[1] < bestScore[0]) {
  2409. char *str, *rest;
  2410. char buf[256];
  2411. int i;
  2412. /*
  2413.  * Fill in the desired pixel size for this font.
  2414.  */
  2415. tryscale:
  2416. str = nameList[bestIdx[1]];
  2417. for (i = 0; i < XLFD_PIXEL_SIZE; i++) {
  2418.     str = strchr(str + 1, '-');
  2419. }
  2420. rest = str;
  2421. for (i = XLFD_PIXEL_SIZE; i < XLFD_CHARSET; i++) {
  2422.     rest = strchr(rest + 1, '-');
  2423. }
  2424. *str = '';
  2425. sprintf(buf, "%.200s-%d-*-*-*-*-*%s", nameList[bestIdx[1]],
  2426. -wantPtr->fa.size, rest);
  2427. *str = '-';
  2428. fontStructPtr = XLoadQueryFont(display, buf);
  2429. bestScore[1] = INT_MAX;
  2430.     }
  2431.     if (fontStructPtr == NULL) {
  2432. fontStructPtr = XLoadQueryFont(display, nameList[bestIdx[0]]);
  2433. if (fontStructPtr == NULL) {
  2434.     /*
  2435.      * This shouldn't happen because the font name is one of the
  2436.      * names that X gave us to use, but it does anyhow.
  2437.      */
  2438.     if (bestScore[1] < INT_MAX) {
  2439. goto tryscale;
  2440.     }
  2441.     return GetSystemFont(display);
  2442. }
  2443.     }
  2444.     return fontStructPtr;
  2445. }
  2446. /*
  2447.  *---------------------------------------------------------------------------
  2448.  *
  2449.  * GetSystemFont --
  2450.  *
  2451.  * Absolute fallback mechanism, called when we need a font and no
  2452.  * other font can be found and/or instantiated.
  2453.  *
  2454.  * Results:
  2455.  * A pointer to a font.  Never NULL.
  2456.  *
  2457.  * Side effects:
  2458.  * If there are NO fonts installed on the system, this call will
  2459.  * panic, but how did you get X running in that case?
  2460.  *
  2461.  *---------------------------------------------------------------------------
  2462.  */
  2463. static XFontStruct *
  2464. GetSystemFont(display)
  2465.     Display *display; /* Display for new XFontStruct. */
  2466. {
  2467.     XFontStruct *fontStructPtr;
  2468.     fontStructPtr = XLoadQueryFont(display, "fixed");
  2469.     if (fontStructPtr == NULL) {
  2470. fontStructPtr = XLoadQueryFont(display, "*");
  2471. if (fontStructPtr == NULL) {
  2472.     panic("TkpGetFontFromAttributes: cannot get any font");
  2473. }
  2474.     }
  2475.     return fontStructPtr;
  2476. }
  2477. /*
  2478.  *---------------------------------------------------------------------------
  2479.  *
  2480.  * GetFontAttributes --
  2481.  *
  2482.  * Given a screen font, determine its actual attributes, which are
  2483.  * not necessarily the attributes that were used to construct it.
  2484.  *
  2485.  * Results:
  2486.  * *faPtr is filled with the screen font's attributes.
  2487.  *
  2488.  * Side effects:
  2489.  * None.
  2490.  *
  2491.  *---------------------------------------------------------------------------
  2492.  */
  2493. static int
  2494. GetFontAttributes(display, fontStructPtr, faPtr)
  2495.     Display *display; /* Display that owns the screen font. */
  2496.     XFontStruct *fontStructPtr; /* Screen font to query. */
  2497.     FontAttributes *faPtr; /* For storing attributes of screen font. */
  2498. {
  2499.     unsigned long value;
  2500.     char *name;
  2501.     
  2502.     if ((XGetFontProperty(fontStructPtr, XA_FONT, &value) != False) &&
  2503.     (value != 0)) {
  2504. name = XGetAtomName(display, (Atom) value);
  2505. if (TkFontParseXLFD(name, &faPtr->fa, &faPtr->xa) != TCL_OK) {
  2506.     faPtr->fa.family = Tk_GetUid(name);
  2507.     faPtr->xa.foundry = Tk_GetUid("");
  2508.     faPtr->xa.charset = Tk_GetUid("");
  2509. }
  2510. XFree(name);
  2511.     } else {
  2512. TkInitFontAttributes(&faPtr->fa);
  2513. TkInitXLFDAttributes(&faPtr->xa);
  2514.     }
  2515.     /*
  2516.      * Do last ditch check for family.  It seems that some X servers can
  2517.      * fail on the X font calls above, slipping through earlier checks.
  2518.      * X-Win32 5.4 is one of these.
  2519.      */
  2520.     if (faPtr->fa.family == NULL) {
  2521. faPtr->fa.family = Tk_GetUid("");
  2522. faPtr->xa.foundry = Tk_GetUid("");
  2523. faPtr->xa.charset = Tk_GetUid("");
  2524.     }
  2525.     return IdentifySymbolEncodings(faPtr);
  2526. }
  2527. /*
  2528.  *---------------------------------------------------------------------------
  2529.  *
  2530.  * ListFonts --
  2531.  *
  2532.  * Utility function to return the array of all XLFDs on the system
  2533.  * with the specified face name.
  2534.  *
  2535.  * Results:
  2536.  * The return value is an array of XLFDs, which should be freed with
  2537.  * XFreeFontNames(), or NULL if no XLFDs matched the requested name.
  2538.  *
  2539.  * Side effects:
  2540.  * None.
  2541.  *
  2542.  *---------------------------------------------------------------------------
  2543.  */
  2544.  
  2545. static char **
  2546. ListFonts(display, faceName, numNamesPtr)
  2547.     Display *display; /* Display to query. */
  2548.     CONST char *faceName; /* Desired face name, or "*" for all. */
  2549.     int *numNamesPtr; /* Filled with length of returned array, or
  2550.  * 0 if no names were found. */
  2551. {
  2552.     char buf[256];
  2553.     sprintf(buf, "-*-%.80s-*-*-*-*-*-*-*-*-*-*-*-*", faceName);
  2554.     return XListFonts(display, buf, 10000, numNamesPtr);
  2555. }
  2556. static char **
  2557. ListFontOrAlias(display, faceName, numNamesPtr)
  2558.     Display *display; /* Display to query. */
  2559.     CONST char *faceName; /* Desired face name, or "*" for all. */
  2560.     int *numNamesPtr; /* Filled with length of returned array, or
  2561.  * 0 if no names were found. */
  2562. {
  2563.     char **nameList, **aliases;
  2564.     int i;
  2565.     
  2566.     nameList = ListFonts(display, faceName, numNamesPtr);
  2567.     if (nameList != NULL) {
  2568. return nameList;
  2569.     }
  2570.     aliases = TkFontGetAliasList(faceName);
  2571.     if (aliases != NULL) {
  2572. for (i = 0; aliases[i] != NULL; i++) {
  2573.     nameList = ListFonts(display, aliases[i], numNamesPtr);
  2574.     if (nameList != NULL) {
  2575. return nameList;
  2576.     }
  2577. }
  2578.     }
  2579.     *numNamesPtr = 0;
  2580.     return NULL;
  2581. }
  2582. /*
  2583.  *---------------------------------------------------------------------------
  2584.  *
  2585.  * IdentifySymbolEncodings --
  2586.  *
  2587.  * If the font attributes refer to a symbol font, update the
  2588.  * charset field of the font attributes so that it reflects the
  2589.  * encoding of that symbol font.  In general, the raw value for
  2590.  * the charset field parsed from an XLFD is meaningless for symbol
  2591.  * fonts.
  2592.  *
  2593.  * Symbol fonts are all fonts whose name appears in the symbolClass.
  2594.  *
  2595.  * Results:
  2596.  * The return value is non-zero if the font attributes specify a
  2597.  * symbol font, or 0 otherwise.  If a non-zero value is returned
  2598.  * the charset field of the font attributes will be changed to
  2599.  * the string that represents the actual encoding for the symbol font.
  2600.  *
  2601.  * Side effects:
  2602.  * None.
  2603.  *
  2604.  *---------------------------------------------------------------------------
  2605.  */
  2606. static int
  2607. IdentifySymbolEncodings(faPtr)
  2608.     FontAttributes *faPtr;
  2609. {
  2610.     int i, j;
  2611.     char **aliases, **symbolClass;
  2612.     symbolClass = TkFontGetSymbolClass();
  2613.     for (i = 0; symbolClass[i] != NULL; i++) {
  2614. if (strcasecmp(faPtr->fa.family, symbolClass[i]) == 0) {
  2615.     faPtr->xa.charset = Tk_GetUid(GetEncodingAlias(symbolClass[i]));
  2616.     return 1;
  2617. }
  2618. aliases = TkFontGetAliasList(symbolClass[i]);
  2619. for (j = 0; (aliases != NULL) && (aliases[j] != NULL); j++) {
  2620.     if (strcasecmp(faPtr->fa.family, aliases[j]) == 0) {
  2621. faPtr->xa.charset = Tk_GetUid(GetEncodingAlias(aliases[j]));
  2622. return 1;
  2623.     }
  2624. }
  2625.     }
  2626.     return 0;
  2627. }
  2628. /*
  2629.  *---------------------------------------------------------------------------
  2630.  *
  2631.  * GetEncodingAlias --
  2632.  *
  2633.  * Map the name of an encoding to another name that should be used
  2634.  * when actually loading the encoding.  For instance, the encodings
  2635.  * "jisc6226.1978", "jisx0208.1983", "jisx0208.1990", and
  2636.  * "jisx0208.1996" are well-known names for the same encoding and
  2637.  * are represented by one encoding table: "jis0208".
  2638.  *
  2639.  * Results:
  2640.  * As above.  If the name has no alias, the original name is returned.
  2641.  *
  2642.  * Side effects:
  2643.  * None.
  2644.  *
  2645.  *---------------------------------------------------------------------------
  2646.  */
  2647. static CONST char *
  2648. GetEncodingAlias(name)
  2649.     CONST char *name; /* The name to look up. */
  2650. {
  2651.     EncodingAlias *aliasPtr;
  2652.     
  2653.     for (aliasPtr = encodingAliases; aliasPtr->aliasPattern != NULL; ) {
  2654. if (Tcl_StringMatch((char *) name, aliasPtr->aliasPattern)) {
  2655.     return aliasPtr->realName;
  2656. }
  2657. aliasPtr++;
  2658.     }
  2659.     return name;
  2660. }