OSDN Git Service

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