4 * Contains the Unix implementation of the platform-independent font
7 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
9 * See the file "license.terms" for information on usage and redistribution of
10 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 #include "tkUnixInt.h"
17 * The preferred font encodings.
20 static const char encodingList[][10] = {
21 "iso8859-1", "jis0208", "jis0212"
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.
32 * Under Unix, there are three attributes that uniquely identify a "font
33 * family": the foundry, face name, and charset.
36 #define FONTMAP_SHIFT 10
38 #define FONTMAP_BITSPERPAGE (1 << FONTMAP_SHIFT)
39 #define FONTMAP_NUMCHARS 0x40000
40 #define FONTMAP_PAGES (FONTMAP_NUMCHARS / FONTMAP_BITSPERPAGE)
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. */
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. */
59 int isTwoByteFont; /* 1 if this is a double-byte font, 0
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. */
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.
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. */
91 * The following structure represents Unix's implementation of a font object.
94 #define SUBFONT_SPACE 3
95 #define BASE_CHARS 256
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
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
115 Display *display; /* Display that owns font. */
116 int pixelSize; /* Original pixel size used when font was
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)
126 int barHeight; /* Height of underline or overstrike bar (used
127 * when drawing underlined or strikeout font)
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.
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. */
146 * Just some utility structures used for passing around values in helper
150 typedef struct FontAttributes {
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
161 FontFamily controlFamily; /* FontFamily used to handle control character
162 * expansions. The encoding of this FontFamily
163 * converts UTF-8 to backslashed escape
165 } ThreadSpecificData;
166 static Tcl_ThreadDataKey dataKey;
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.
173 static const EncodingAlias encodingAliases[] = {
174 {"gb2312-raw", "gb2312*"},
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"},
193 * Functions used only in this file.
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,
229 static void InitSubFont(Display *display,
230 XFontStruct *fontStructPtr, int base,
231 SubFont *subFontPtr);
232 static char ** ListFonts(Display *display, const char *faceName,
234 static char ** ListFontOrAlias(Display *display, const char*faceName,
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);
251 *-------------------------------------------------------------------------
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.
263 * Releases thread-specific resources used by font pkg.
265 *-------------------------------------------------------------------------
272 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
273 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
275 if (tsdPtr->controlFamily.encoding != NULL) {
276 FontFamily *familyPtr = &tsdPtr->controlFamily;
279 Tcl_FreeEncoding(familyPtr->encoding);
280 for (i = 0; i < FONTMAP_PAGES; i++) {
281 if (familyPtr->fontMap[i] != NULL) {
282 ckfree(familyPtr->fontMap[i]);
285 tsdPtr->controlFamily.encoding = NULL;
290 *-------------------------------------------------------------------------
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.
304 *-------------------------------------------------------------------------
309 TCL_UNUSED(TkMainInfo *)) /* The application being created. */
311 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
312 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
317 if (tsdPtr->controlFamily.encoding == NULL) {
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;
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);
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.
336 ucs2 = Tcl_GetEncoding(NULL, "ucs-2be");
338 Tcl_EncodingType ucs2type = {"ucs-2be", Ucs2beToUtfProc, UtfToUcs2beProc, NULL, NULL, 2};
339 Tcl_CreateEncoding(&ucs2type);
341 Tcl_FreeEncoding(ucs2);
343 Tcl_CreateThreadExitHandler(FontPkgCleanup, NULL);
348 *-------------------------------------------------------------------------
352 * Convert from UTF-8 into the ASCII expansion of a control character.
355 * Returns TCL_OK if conversion was successful.
360 *-------------------------------------------------------------------------
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
376 int dstLen, /* The maximum length of output buffer in
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
383 int *dstWrotePtr, /* Filled with the number of bytes that were
384 * stored in the output buffer as a result of
386 int *dstCharsPtr) /* Filled with the number of characters that
387 * correspond to the bytes stored in the
390 const char *srcStart, *srcEnd;
391 char *dstStart, *dstEnd;
393 static const char hexChars[] = "0123456789abcdef";
394 static const char mapChars[] = {
396 'a', 'b', 't', 'n', 'v', 'f', 'r'
402 srcEnd = src + srcLen;
405 dstEnd = dst + dstLen - 6;
407 for ( ; src < srcEnd; ) {
409 result = TCL_CONVERT_NOSPACE;
412 src += TkUtfToUniChar(src, &ch);
414 if (((size_t)ch < sizeof(mapChars)) && (mapChars[ch] != 0)) {
415 dst[1] = mapChars[ch];
417 } else if ((size_t)ch < 256) {
419 dst[2] = hexChars[(ch >> 4) & 0xF];
420 dst[3] = hexChars[ch & 0xF];
422 } else if ((size_t)ch < 0x10000) {
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];
430 /* TODO we can do better here */
439 *srcReadPtr = src - srcStart;
440 *dstWrotePtr = dst - dstStart;
441 *dstCharsPtr = dst - dstStart;
446 *-------------------------------------------------------------------------
450 * Convert from UCS-2BE (big-endian 16-bit Unicode) to UTF-8.
453 * Returns TCL_OK if conversion was successful.
458 *-------------------------------------------------------------------------
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
474 int dstLen, /* The maximum length of output buffer in
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
481 int *dstWrotePtr, /* Filled with the number of bytes that were
482 * stored in the output buffer as a result of
484 int *dstCharsPtr) /* Filled with the number of characters that
485 * correspond to the bytes stored in the
488 const char *srcStart, *srcEnd;
489 const char *dstEnd, *dstStart;
490 int result, numChars, charLimit = INT_MAX;
493 if (flags & TCL_ENCODING_CHAR_LIMIT) {
494 charLimit = *dstCharsPtr;
498 /* check alignment with ucs-2 (2 == sizeof(UCS-2)) */
499 if ((srcLen % 2) != 0) {
500 result = TCL_CONVERT_MULTIBYTE;
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;
510 srcEnd = src + srcLen;
513 dstEnd = dst + dstLen - 4;
515 for (numChars = 0; src < srcEnd && numChars <= charLimit; numChars++) {
517 result = TCL_CONVERT_NOSPACE;
521 ch = (src[0] & 0xFF) << 8 | (src[1] & 0xFF);
522 src += 2 /* sizeof(UTF-16) */;
525 * Special case for 1-byte utf chars for speed. Make sure we work with
526 * unsigned short-size data.
528 if (ch && ch < 0x80) {
529 *dst++ = (ch & 0xFF);
531 dst += Tcl_UniCharToUtf(ch, dst);
535 *srcReadPtr = src - srcStart;
536 *dstWrotePtr = dst - dstStart;
537 *dstCharsPtr = numChars;
542 *-------------------------------------------------------------------------
546 * Convert from UTF-8 to UCS-2BE (fixed 2-byte encoding).
549 * Returns TCL_OK if conversion was successful.
554 *-------------------------------------------------------------------------
559 TCL_UNUSED(void *), /* TableEncodingData that specifies
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
571 int dstLen, /* The maximum length of output buffer in
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
578 int *dstWrotePtr, /* Filled with the number of bytes that were
579 * stored in the output buffer as a result of
581 int *dstCharsPtr) /* Filled with the number of characters that
582 * correspond to the bytes stored in the
585 const char *srcStart, *srcEnd, *srcClose, *dstStart, *dstEnd;
586 int result, numChars;
590 srcEnd = src + srcLen;
592 if (!(flags & TCL_ENCODING_END)) {
597 dstEnd = dst + dstLen - 2 /* sizeof(UCS-2) */;
600 for (numChars = 0; src < srcEnd; numChars++) {
601 if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) {
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.
606 result = TCL_CONVERT_MULTIBYTE;
610 result = TCL_CONVERT_NOSPACE;
613 src += TkUtfToUniChar(src, &ch);
619 * Ensure big-endianness (store big bits first).
622 *dst++ = (char)((ch >> 8) & 0xFF);
623 *dst++ = (char)(ch & 0xFF);
625 *srcReadPtr = src - srcStart;
626 *dstWrotePtr = dst - dstStart;
627 *dstCharsPtr = numChars;
632 *---------------------------------------------------------------------------
634 * TkpGetNativeFont --
636 * Map a platform-specific native font name to a TkFont.
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.
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.
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().
654 *---------------------------------------------------------------------------
659 Tk_Window tkwin, /* For display where font will be used. */
660 const char *name) /* Platform-specific font name. */
663 XFontStruct *fontStructPtr;
666 int hasSpace, dashes, hasWild;
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
678 hasSpace = dashes = hasWild = 0;
679 for (p = name; *p != '\0'; p++) {
685 } else if (*p == '-') {
687 } else if (*p == '*') {
691 if ((dashes < 14) && !hasWild && hasSpace) {
695 fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), name);
696 if (fontStructPtr == NULL) {
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
706 if (name[0] == '-') {
707 if (name[1] != '*') {
710 dash = strchr(name + 1, '-');
711 if ((dash == NULL) || (isspace(UCHAR(dash[-1])))) {
715 } else if (name[0] != '*') {
718 if (TkFontParseXLFD(name, &fa.fa, &fa.xa) != TCL_OK) {
721 fontStructPtr = CreateClosestFont(tkwin, &fa.fa, &fa.xa);
723 fontPtr = (UnixFont *)ckalloc(sizeof(UnixFont));
724 InitFont(tkwin, fontStructPtr, fontPtr);
726 return (TkFont *) fontPtr;
730 *---------------------------------------------------------------------------
732 * TkpGetFontFromAttributes --
734 * Given a desired set of attributes for a font, find a font with the
735 * closest matching attributes.
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
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.
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().
755 *---------------------------------------------------------------------------
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. */
772 XFontStruct *fontStructPtr;
774 TkInitXLFDAttributes(&xa);
775 fontStructPtr = CreateClosestFont(tkwin, faPtr, &xa);
777 fontPtr = (UnixFont *) tkFontPtr;
778 if (fontPtr == NULL) {
779 fontPtr = (UnixFont *)ckalloc(sizeof(UnixFont));
781 ReleaseFont(fontPtr);
783 InitFont(tkwin, fontStructPtr, fontPtr);
785 fontPtr->font.fa.underline = faPtr->underline;
786 fontPtr->font.fa.overstrike = faPtr->overstrike;
788 return (TkFont *) fontPtr;
792 *---------------------------------------------------------------------------
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
805 * TkFont is deallocated.
807 *---------------------------------------------------------------------------
812 TkFont *tkFontPtr) /* Token of font to be deleted. */
814 UnixFont *fontPtr = (UnixFont *) tkFontPtr;
816 ReleaseFont(fontPtr);
820 *---------------------------------------------------------------------------
822 * TkpGetFontFamilies --
824 * Return information about the font families that are available on the
825 * display of the given window.
828 * Modifies interp's result object to hold a list of all the available
834 *---------------------------------------------------------------------------
839 Tcl_Interp *interp, /* Interp to hold result. */
840 Tk_Window tkwin) /* For display to query. */
842 int i, isNew, numNames;
843 char *family, **nameList;
844 Tcl_HashTable familyTable;
846 Tcl_HashSearch search;
847 Tcl_Obj *resultPtr, *strPtr;
849 Tcl_InitHashTable(&familyTable, TCL_STRING_KEYS);
850 nameList = ListFonts(Tk_Display(tkwin), "*", &numNames);
851 for (i = 0; i < numNames; i++) {
854 family = strchr(nameList[i] + 1, '-');
855 if (family == NULL) {
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]
865 family++; /* Advance to char after '-'. */
866 familyEnd = strchr(family, '-');
867 if (familyEnd == NULL) {
868 continue; /* See comment above. */
871 Tcl_CreateHashEntry(&familyTable, family, &isNew);
873 XFreeFontNames(nameList);
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);
882 Tcl_SetObjResult(interp, resultPtr);
884 Tcl_DeleteHashTable(&familyTable);
888 *-------------------------------------------------------------------------
892 * A function used by the testing package for querying the actual screen
893 * fonts that make up a font object.
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.
902 *-------------------------------------------------------------------------
911 Tcl_Obj *objv[3], *resultPtr, *listPtr;
913 FontFamily *familyPtr;
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);
926 Tcl_SetObjResult(interp, resultPtr);
930 *----------------------------------------------------------------------
932 * TkpGetFontAttrsForChar --
934 * Retrieve the font attributes of the actual font used to render a given
941 * The font attributes are stored in *faPtr.
943 *----------------------------------------------------------------------
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 */
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
964 GetFontAttributes(Tk_Display(tkwin), thisSubFontPtr->fontStructPtr, &atts);
969 *---------------------------------------------------------------------------
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
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.
986 *---------------------------------------------------------------------------
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
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
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. */
1013 SubFont *lastSubFontPtr;
1014 int curX, curByte, ch;
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.
1023 fontPtr = (UnixFont *) tkfont;
1025 lastSubFontPtr = &fontPtr->subFontArray[0];
1027 if (numBytes == 0) {
1030 } else if (maxLength < 0) {
1031 const char *p, *end, *next;
1032 SubFont *thisSubFontPtr;
1033 FontFamily *familyPtr;
1034 Tcl_DString runString;
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.
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);
1058 curX += XTextWidth(lastSubFontPtr->fontStructPtr,
1059 Tcl_DStringValue(&runString),
1060 Tcl_DStringLength(&runString));
1062 Tcl_DStringFree(&runString);
1063 lastSubFontPtr = thisSubFontPtr;
1068 familyPtr = lastSubFontPtr->familyPtr;
1069 Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source,
1071 if (familyPtr->isTwoByteFont) {
1072 curX += XTextWidth16(lastSubFontPtr->fontStructPtr,
1073 (XChar2b *) Tcl_DStringValue(&runString),
1074 Tcl_DStringLength(&runString) >> 1);
1076 curX += XTextWidth(lastSubFontPtr->fontStructPtr,
1077 Tcl_DStringValue(&runString),
1078 Tcl_DStringLength(&runString));
1080 Tcl_DStringFree(&runString);
1083 const char *p, *end, *next, *term;
1084 int newX, termX, sawNonSpace, dstWrote;
1085 FontFamily *familyPtr;
1089 * How many chars will fit in the space allotted? This first version
1090 * may be inefficient because it measures every character
1094 next = source + TkUtfToUniChar(source, &ch);
1095 newX = curX = termX = 0;
1098 end = source + numBytes;
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];
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);
1114 newX += XTextWidth(lastSubFontPtr->fontStructPtr,
1115 (char *)&buf[0].byte1, dstWrote);
1118 if (newX > maxLength) {
1129 next += TkUtfToUniChar(next, &ch);
1130 if ((ch < 256) && isspace(ch)) {
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.
1146 if ((flags & TK_PARTIAL_OK) && (p < end) && (curX < maxLength)) {
1148 * Include the first character that didn't quite fit in the
1149 * desired span. The width returned will include the width of that
1154 p += TkUtfToUniChar(p, &ch);
1156 if ((flags & TK_AT_LEAST_ONE) && (term == source) && (p < end)) {
1159 if (term == source) {
1160 term += TkUtfToUniChar(term, &ch);
1163 } else if ((p >= end) || !(flags & TK_WHOLE_WORDS)) {
1169 curByte = term - source;
1177 *---------------------------------------------------------------------------
1179 * TkpMeasureCharsInContext --
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
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().
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.
1198 *---------------------------------------------------------------------------
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. */
1228 return Tk_MeasureChars(tkfont, source + rangeStart, rangeLength,
1229 maxLength, flags, lengthPtr);
1233 *---------------------------------------------------------------------------
1237 * Draw a string of characters on the screen. Tk_DrawChars() expands
1238 * control characters that occur in the string to \xNN sequences.
1244 * Information gets drawn on the screen.
1246 *---------------------------------------------------------------------------
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. */
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
1275 unsigned width, height, border_width, depth;
1279 lastSubFontPtr = &fontPtr->subFontArray[0];
1282 #ifdef TK_DRAW_CHAR_XWINDOW_CHECK
1284 * Get the window width so we can abort drawing outside of the window
1287 if (XGetGeometry(display, drawable, &root, &rx, &ry, &width, &height,
1288 &border_width, &depth) == False) {
1289 window_width = INT_MAX;
1291 window_width = width;
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).
1299 window_width = 32768;
1302 end = source + numBytes;
1303 needWidth = fontPtr->font.fa.underline + fontPtr->font.fa.overstrike;
1304 for (p = source; p <= end; ) {
1306 next = p + TkUtfToUniChar(p, &ch);
1307 thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
1310 thisSubFontPtr = lastSubFontPtr;
1312 if ((thisSubFontPtr != lastSubFontPtr)
1313 || (p == end) || (p-source > 200)) {
1315 do_width = (needWidth || (p != end)) ? 1 : 0;
1316 familyPtr = lastSubFontPtr->familyPtr;
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);
1325 x += XTextWidth16(lastSubFontPtr->fontStructPtr,
1326 (XChar2b *) Tcl_DStringValue(&runString),
1327 Tcl_DStringLength(&runString) / 2);
1330 XDrawString(display, drawable, gc, x, y,
1331 Tcl_DStringValue(&runString),
1332 Tcl_DStringLength(&runString));
1334 x += XTextWidth(lastSubFontPtr->fontStructPtr,
1335 Tcl_DStringValue(&runString),
1336 Tcl_DStringLength(&runString));
1339 Tcl_DStringFree(&runString);
1341 lastSubFontPtr = thisSubFontPtr;
1343 XSetFont(display, gc, lastSubFontPtr->fontStructPtr->fid);
1344 if (x > window_width) {
1351 if (lastSubFontPtr != &fontPtr->subFontArray[0]) {
1352 XSetFont(display, gc, fontPtr->subFontArray[0].fontStructPtr->fid);
1355 if (fontPtr->font.fa.underline != 0) {
1356 XFillRectangle(display, drawable, gc, xStart,
1357 y + fontPtr->underlinePos,
1358 (unsigned) (x - xStart), (unsigned) fontPtr->barHeight);
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);
1368 *---------------------------------------------------------------------------
1370 * TkpDrawCharsInContext --
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().
1376 * Note: TK_DRAW_IN_CONTEXT being currently defined only on macOS, this
1377 * function is unused (and possibly unfinished). See [7655f65ae7].
1383 * Information gets drawn on the screen.
1385 *---------------------------------------------------------------------------
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
1409 int widthUntilStart;
1411 Tk_MeasureChars(tkfont, source, rangeStart, -1, 0, &widthUntilStart);
1412 Tk_DrawChars(display, drawable, gc, tkfont, source + rangeStart,
1413 rangeLength, x+widthUntilStart, y);
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
1436 double angle) /* What angle to put text at, in degrees. */
1438 int widthUntilStart;
1439 double sinA = sin(angle * PI/180.0), cosA = cos(angle * PI/180.0);
1441 (void) numBytes; /*unused*/
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);
1449 *-------------------------------------------------------------------------
1451 * CreateClosestFont --
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.
1464 * Return value is the XFontStruct that best matched the requested
1465 * attributes. The return value is never NULL; some font will always be
1471 *-------------------------------------------------------------------------
1474 static XFontStruct *
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. */
1482 FontAttributes want;
1484 int numNames, nameIdx, bestIdx[2];
1486 XFontStruct *fontStructPtr;
1487 unsigned bestScore[2];
1492 if (want.xa.foundry == NULL) {
1493 want.xa.foundry = Tk_GetUid("adobe");
1495 if (want.fa.family == NULL) {
1496 want.fa.family = Tk_GetUid("fixed");
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. */
1503 display = Tk_Display(tkwin);
1506 * Algorithm to get the closest font to the name requested.
1509 * try all aliases for fontname
1510 * foreach fallback for fontname
1512 * try all aliases for the fallback
1515 nameList = ListFontOrAlias(display, want.fa.family, &numNames);
1516 if (numNames == 0) {
1517 const char *const *const *fontFallbacks;
1519 const char *fallback;
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) {
1528 if (fallback != NULL) {
1529 for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {
1530 nameList = ListFontOrAlias(display, fallback, &numNames);
1531 if (numNames != 0) {
1537 nameList = ListFonts(display, "fixed", &numNames);
1538 if (numNames == 0) {
1539 nameList = ListFonts(display, "*", &numNames);
1541 if (numNames == 0) {
1542 return GetSystemFont(display);
1549 bestScore[0] = (unsigned) -1;
1550 bestScore[1] = (unsigned) -1;
1551 for (nameIdx = 0; nameIdx < numNames; nameIdx++) {
1556 if (TkFontParseXLFD(nameList[nameIdx], &got.fa, &got.xa) != TCL_OK) {
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;
1571 fontStructPtr = GetScreenFont(display, &want, nameList, bestIdx,
1573 XFreeFontNames(nameList);
1575 if (fontStructPtr == NULL) {
1576 return GetSystemFont(display);
1578 return fontStructPtr;
1582 *---------------------------------------------------------------------------
1586 * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().
1587 * Initializes the memory for a new UnixFont that wraps the
1588 * platform-specific data.
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().
1595 * Fills the WinFont structure.
1600 *---------------------------------------------------------------------------
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. */
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;
1615 TkFontAttributes *faPtr;
1616 TkFontMetrics *fmPtr;
1617 SubFont *controlPtr, *subFontPtr;
1622 * Get all font attributes and metrics.
1625 display = Tk_Display(tkwin);
1626 GetFontAttributes(display, fontStructPtr, &fa);
1628 minHi = fontStructPtr->min_byte1;
1629 maxHi = fontStructPtr->max_byte1;
1630 minLo = fontStructPtr->min_char_or_byte2;
1631 maxLo = fontStructPtr->max_char_or_byte2;
1634 if (fontStructPtr->per_char != NULL) {
1636 limit = (maxHi - minHi + 1) * (maxLo - minLo + 1);
1637 for (i = 0; i < limit; i++) {
1638 n = fontStructPtr->per_char[i].width;
1642 } else if (width != n) {
1650 fontPtr->font.fid = fontStructPtr->fid;
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;
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;
1666 fontPtr->display = display;
1667 fontPtr->pixelSize = (int)(TkFontGetPixels(tkwin, fa.fa.size) + 0.5);
1668 fontPtr->xa = fa.xa;
1670 fontPtr->numSubFonts = 1;
1671 fontPtr->subFontArray = fontPtr->staticSubFonts;
1672 InitSubFont(display, fontStructPtr, 1, &fontPtr->subFontArray[0]);
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;
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)) {
1686 } else if (fontStructPtr->per_char == NULL) {
1687 n = fontStructPtr->max_bounds.width;
1689 n = fontStructPtr->per_char[i - minLo].width;
1691 fontPtr->widths[i] = n;
1694 if (XGetFontProperty(fontStructPtr, XA_UNDERLINE_POSITION, &value)) {
1695 fontPtr->underlinePos = value;
1698 * If the XA_UNDERLINE_POSITION property does not exist, the X manual
1699 * recommends using the following value:
1702 fontPtr->underlinePos = fontStructPtr->descent / 2;
1704 fontPtr->barHeight = 0;
1705 if (XGetFontProperty(fontStructPtr, XA_UNDERLINE_THICKNESS, &value)) {
1706 fontPtr->barHeight = value;
1708 if (fontPtr->barHeight == 0) {
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.
1716 fontPtr->barHeight = fontPtr->widths[(unsigned char)'I'] / 3;
1717 if (fontPtr->barHeight == 0) {
1718 fontPtr->barHeight = 1;
1721 if (fontPtr->underlinePos + fontPtr->barHeight > fontStructPtr->descent) {
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.
1728 fontPtr->barHeight = fontStructPtr->descent - fontPtr->underlinePos;
1729 if (fontPtr->barHeight == 0) {
1730 fontPtr->underlinePos--;
1731 fontPtr->barHeight = 1;
1737 *-------------------------------------------------------------------------
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.
1750 *---------------------------------------------------------------------------
1755 UnixFont *fontPtr) /* The font to delete. */
1759 for (i = 0; i < fontPtr->numSubFonts; i++) {
1760 ReleaseSubFont(fontPtr->display, &fontPtr->subFontArray[i]);
1762 if (fontPtr->subFontArray != fontPtr->staticSubFonts) {
1763 ckfree(fontPtr->subFontArray);
1768 *-------------------------------------------------------------------------
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.
1777 * The subFontPtr is filled with information about the font.
1782 *-------------------------------------------------------------------------
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
1794 subFontPtr->fontStructPtr = fontStructPtr;
1795 subFontPtr->familyPtr = AllocFontFamily(display, fontStructPtr, base);
1796 subFontPtr->fontMap = subFontPtr->familyPtr->fontMap;
1800 *-------------------------------------------------------------------------
1804 * Called to release the contents of a SubFont. The caller is responsible
1805 * for freeing the memory used by the SubFont itself.
1811 * Memory and resources are freed.
1813 *---------------------------------------------------------------------------
1818 Display *display, /* Display which owns screen font. */
1819 SubFont *subFontPtr) /* The SubFont to delete. */
1821 XFreeFont(display, subFontPtr->fontStructPtr);
1822 FreeFontFamily(subFontPtr->familyPtr);
1826 *-------------------------------------------------------------------------
1828 * AllocFontFamily --
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.
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.
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
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.
1849 *-------------------------------------------------------------------------
1854 Display *display, /* Display in which font will be used. */
1855 XFontStruct *fontStructPtr, /* Screen font whose FontFamily is to be
1857 TCL_UNUSED(int)) /* Non-zero if this font family is to be used
1858 * in the base font of a font object. */
1860 FontFamily *familyPtr;
1862 Tcl_Encoding encoding;
1863 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1864 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1866 GetFontAttributes(display, fontStructPtr, &fa);
1867 encoding = Tcl_GetEncoding(NULL, GetEncodingAlias(fa.xa.charset));
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)) {
1875 Tcl_FreeEncoding(encoding);
1877 familyPtr->refCount++;
1882 familyPtr = (FontFamily *)ckalloc(sizeof(FontFamily));
1883 memset(familyPtr, 0, sizeof(FontFamily));
1884 familyPtr->nextPtr = tsdPtr->fontFamilyList;
1885 tsdPtr->fontFamilyList = familyPtr;
1888 * Set key for this FontFamily.
1891 familyPtr->foundry = fa.xa.foundry;
1892 familyPtr->faceName = fa.fa.family;
1893 familyPtr->encoding = encoding;
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.
1901 familyPtr->refCount = 2;
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
1909 familyPtr->isTwoByteFont = !(
1910 (fontStructPtr->min_byte1 == 0) &&
1911 (fontStructPtr->max_byte1 == 0) &&
1912 (fontStructPtr->max_char_or_byte2 < 256));
1917 *-------------------------------------------------------------------------
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.
1931 *-------------------------------------------------------------------------
1936 FontFamily *familyPtr) /* The FontFamily to delete. */
1938 FontFamily **familyPtrPtr;
1939 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1940 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1943 if (familyPtr == NULL) {
1946 if (familyPtr->refCount-- > 1) {
1949 if (familyPtr->encoding) {
1950 Tcl_FreeEncoding(familyPtr->encoding);
1952 for (i = 0; i < FONTMAP_PAGES; i++) {
1953 if (familyPtr->fontMap[i] != NULL) {
1954 ckfree(familyPtr->fontMap[i]);
1962 for (familyPtrPtr = &tsdPtr->fontFamilyList; ; ) {
1963 if (*familyPtrPtr == familyPtr) {
1964 *familyPtrPtr = familyPtr->nextPtr;
1967 familyPtrPtr = &(*familyPtrPtr)->nextPtr;
1974 *-------------------------------------------------------------------------
1976 * FindSubFontForChar --
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.
1984 * The return value is the SubFont to use to display the given character.
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.
1993 *-------------------------------------------------------------------------
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. */
2004 int i, j, k, numNames;
2006 const char *fallback;
2007 const char *const *aliases;
2009 const char *const *anyFallbacks;
2010 const char *const *const *fontFallbacks;
2011 SubFont *subFontPtr;
2014 if (ch < 0 || ch >= FONTMAP_NUMCHARS) {
2018 for (i = 0; i < fontPtr->numSubFonts; i++) {
2019 if (FontMapLookup(&fontPtr->subFontArray[i], ch)) {
2020 return &fontPtr->subFontArray[i];
2024 if (FontMapLookup(&fontPtr->controlSubFont, ch)) {
2025 return &fontPtr->controlSubFont;
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.
2033 Tcl_DStringInit(&ds);
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
2042 faceName = fontPtr->font.fa.family;
2043 if (SeenName(faceName, &ds) == 0) {
2044 subFontPtr = CanUseFallback(fontPtr, faceName, ch, fixSubFontPtrPtr);
2045 if (subFontPtr != NULL) {
2050 aliases = TkFontGetAliasList(faceName);
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) {
2058 * If the base font has a fallback...
2062 } else if (aliases != NULL) {
2064 * Or if an alias for the base font has a fallback...
2067 for (k = 0; aliases[k] != NULL; k++) {
2068 if (strcasecmp(fallback, aliases[k]) == 0) {
2079 * ...then see if we can use one of the fallbacks, or an alias for one
2083 for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {
2084 subFontPtr = CanUseFallbackWithAliases(fontPtr, fallback, ch, &ds,
2086 if (subFontPtr != NULL) {
2093 * See if we can use something from the global fallback list.
2096 anyFallbacks = TkFontGetGlobalClass();
2097 for (i = 0; (fallback = anyFallbacks[i]) != NULL; i++) {
2098 subFontPtr = CanUseFallbackWithAliases(fontPtr, fallback, ch, &ds,
2100 if (subFontPtr != NULL) {
2106 * Try all face names available in the whole system until we find one that
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,
2117 if (subFontPtr != NULL) {
2118 XFreeFontNames(nameList);
2123 XFreeFontNames(nameList);
2126 Tcl_DStringFree(&ds);
2128 if (subFontPtr == NULL) {
2130 * No font can display this character, so it will be displayed as a
2131 * control character expansion.
2134 subFontPtr = &fontPtr->controlSubFont;
2135 FontMapInsert(subFontPtr, ch);
2141 *-------------------------------------------------------------------------
2145 * See if the screen font can display the given character.
2148 * The return value is 0 if the screen font cannot display the character,
2149 * non-zero otherwise.
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.
2157 *-------------------------------------------------------------------------
2162 SubFont *subFontPtr, /* Contains font mapping cache to be queried
2163 * and possibly updated. */
2164 int ch) /* Character to be tested. */
2168 if (ch < 0 || ch >= FONTMAP_NUMCHARS) {
2171 row = ch >> FONTMAP_SHIFT;
2172 if (subFontPtr->fontMap[row] == NULL) {
2173 FontMapLoadPage(subFontPtr, row);
2175 bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);
2176 return (subFontPtr->fontMap[row][bitOffset >> 3] >> (bitOffset & 7)) & 1;
2180 *-------------------------------------------------------------------------
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.
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.
2200 *-------------------------------------------------------------------------
2205 SubFont *subFontPtr, /* Contains font mapping cache to be
2207 int ch) /* Character to be added to cache. */
2211 if (ch >= 0 && ch < FONTMAP_NUMCHARS) {
2212 row = ch >> FONTMAP_SHIFT;
2213 if (subFontPtr->fontMap[row] == NULL) {
2214 FontMapLoadPage(subFontPtr, row);
2216 bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);
2217 subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);
2222 *-------------------------------------------------------------------------
2224 * FontMapLoadPage --
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.
2237 *-------------------------------------------------------------------------
2241 SubFont *subFontPtr, /* Contains font mapping cache to be
2243 int row) /* Index of the page to be loaded into the
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));
2255 subFontPtr->fontMap[row] = (char *)ckalloc(FONTMAP_BITSPERPAGE / 8);
2256 memset(subFontPtr->fontMap[row], 0, FONTMAP_BITSPERPAGE / 8);
2258 if (subFontPtr->familyPtr == &tsdPtr->controlFamily) {
2262 fontStructPtr = subFontPtr->fontStructPtr;
2263 encoding = subFontPtr->familyPtr->encoding;
2264 isTwoByteFont = subFontPtr->familyPtr->isTwoByteFont;
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;
2274 if (! isTwoByteFont) {
2280 end = (row + 1) << FONTMAP_SHIFT;
2281 for (i = row << FONTMAP_SHIFT; i < end; i++) {
2284 if (Tcl_UtfToExternal(NULL, encoding, src, TkUniCharToUtf(i, src),
2285 TCL_ENCODING_STOPONERROR, NULL, buf, sizeof(buf), NULL,
2286 NULL, NULL) != TCL_OK) {
2289 if (isTwoByteFont) {
2290 hi = ((unsigned char *) buf)[0];
2291 lo = ((unsigned char *) buf)[1];
2294 lo = ((unsigned char *) buf)[0];
2296 if ((hi < minHi) || (hi > maxHi) || (lo < checkLo) || (lo > maxLo)) {
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);
2308 *---------------------------------------------------------------------------
2310 * CanUseFallbackWithAliases --
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.
2317 * See CanUseFallback().
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.
2326 *---------------------------------------------------------------------------
2330 CanUseFallbackWithAliases(
2331 UnixFont *fontPtr, /* The font object that will own the new
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. */
2343 SubFont *subFontPtr;
2344 const char *const *aliases;
2347 if (SeenName(faceName, nameTriedPtr) == 0) {
2348 subFontPtr = CanUseFallback(fontPtr, faceName, ch, fixSubFontPtrPtr);
2349 if (subFontPtr != NULL) {
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,
2359 if (subFontPtr != NULL) {
2369 *---------------------------------------------------------------------------
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
2378 * The return value is 0 if this face name has not already been seen,
2379 * non-zero otherwise.
2384 *---------------------------------------------------------------------------
2389 const char *name, /* The name to check. */
2390 Tcl_DString *dsPtr) /* Contains names that have already been
2393 const char *seen, *end;
2395 seen = Tcl_DStringValue(dsPtr);
2396 end = seen + Tcl_DStringLength(dsPtr);
2397 while (seen < end) {
2398 if (strcasecmp(seen, name) == 0) {
2401 seen += strlen(seen) + 1;
2403 Tcl_DStringAppend(dsPtr, name, (int) (strlen(name) + 1));
2408 *-------------------------------------------------------------------------
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
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.
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.
2431 *-------------------------------------------------------------------------
2436 UnixFont *fontPtr, /* The font object that will own the new
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. */
2444 int i, nameIdx, numNames, srcLen, numEncodings, bestIdx[2];
2446 const char *charset, *hateCharset;
2447 unsigned bestScore[2];
2449 char **nameListOrig;
2451 FontAttributes want, got;
2454 XFontStruct *fontStructPtr;
2455 Tcl_DString dsEncodings;
2456 Tcl_Encoding *encodingCachePtr;
2459 * Assume: the face name is times.
2460 * Assume: adobe:times:iso8859-1 has already been used.
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).
2473 display = fontPtr->display;
2474 nameList = ListFonts(display, faceName, &numNames);
2475 if (numNames == 0) {
2478 nameListOrig = nameList;
2480 srcLen = TkUniCharToUtf(ch, src);
2482 want.fa = fontPtr->font.fa;
2483 want.xa = fontPtr->xa;
2485 want.fa.family = Tk_GetUid(faceName);
2486 want.fa.size = (double)-fontPtr->pixelSize;
2491 Tcl_DStringInit(&dsEncodings);
2493 charset = NULL; /* numNames must be > 0 to get here. */
2498 bestScore[0] = (unsigned) -1;
2499 bestScore[1] = (unsigned) -1;
2500 for (nameIdx = 0; nameIdx < numNames; nameIdx++) {
2501 Tcl_Encoding encoding;
2503 int scalable, srcRead, dstWrote;
2506 if (nameList[nameIdx] == NULL) {
2509 if (TkFontParseXLFD(nameList[nameIdx], &got.fa, &got.xa) != TCL_OK) {
2512 IdentifySymbolEncodings(&got);
2513 charset = GetEncodingAlias(got.xa.charset);
2514 if (hateFoundry != NULL) {
2516 * E. If the font we picked cannot actually display the character,
2517 * cross out all names with the same foundry and encoding.
2520 if ((hateFoundry == got.xa.foundry)
2521 && (strcmp(hateCharset, charset) == 0)) {
2526 * B. Cross out all names whose encodings we've already used.
2529 for (i = 0; i < fontPtr->numSubFonts; i++) {
2530 encoding = fontPtr->subFontArray[i].familyPtr->encoding;
2531 if (strcmp(charset, Tcl_GetEncodingName(encoding)) == 0) {
2538 * C. Cross out all names whose encoding cannot handle the character.
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) {
2549 encoding = Tcl_GetEncoding(NULL, charset);
2550 if (encoding == NULL) {
2554 Tcl_DStringAppend(&dsEncodings, (char *) &encoding,
2558 Tcl_UtfToExternal(NULL, encoding, src, srcLen,
2559 TCL_ENCODING_STOPONERROR, NULL, dst, sizeof(dst), &srcRead,
2561 if (dstWrote == 0) {
2566 * D. Rank each name and pick the best match.
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;
2581 if (nameList == nameListOrig) {
2583 * Not allowed to change pointers to memory that X gives you, so
2587 nameList = (char **)ckalloc(numNames * sizeof(char *));
2588 memcpy(nameList, nameListOrig, numNames * sizeof(char *));
2590 nameList[nameIdx] = NULL;
2593 fontStructPtr = GetScreenFont(display, &want, nameList, bestIdx,
2596 encodingCachePtr = (Tcl_Encoding *) Tcl_DStringValue(&dsEncodings);
2597 for (i = numEncodings; --i >= 0; encodingCachePtr++) {
2598 Tcl_FreeEncoding(*encodingCachePtr);
2600 Tcl_DStringFree(&dsEncodings);
2603 if (fontStructPtr == NULL) {
2604 if (nameList != nameListOrig) {
2607 XFreeFontNames(nameListOrig);
2611 InitSubFont(display, fontStructPtr, 0, &subFont);
2612 if (FontMapLookup(&subFont, ch) == 0) {
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
2619 hateFoundry = got.xa.foundry;
2620 hateCharset = charset;
2621 ReleaseSubFont(display, &subFont);
2624 if (nameList != nameListOrig) {
2627 XFreeFontNames(nameListOrig);
2629 if (fontPtr->numSubFonts >= SUBFONT_SPACE) {
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;
2638 if (fixSubFontPtr != &fontPtr->controlSubFont) {
2640 newPtr + (fixSubFontPtr - fontPtr->subFontArray);
2643 if (fontPtr->subFontArray != fontPtr->staticSubFonts) {
2644 ckfree(fontPtr->subFontArray);
2646 fontPtr->subFontArray = newPtr;
2648 fontPtr->subFontArray[fontPtr->numSubFonts] = subFont;
2649 fontPtr->numSubFonts++;
2650 return &fontPtr->subFontArray[fontPtr->numSubFonts - 1];
2654 *---------------------------------------------------------------------------
2658 * Determine how close the attributes of the font in question match the
2659 * attributes that we want.
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.
2668 *---------------------------------------------------------------------------
2673 FontAttributes *wantPtr, /* The desired attributes. */
2674 FontAttributes *gotPtr) /* The attributes we have to live with. */
2679 if (gotPtr->xa.foundry != wantPtr->xa.foundry) {
2682 if (gotPtr->fa.family != wantPtr->fa.family) {
2685 if (gotPtr->fa.weight != wantPtr->fa.weight) {
2688 if (gotPtr->fa.slant != wantPtr->fa.slant) {
2691 if (gotPtr->xa.slant != wantPtr->xa.slant) {
2694 if (gotPtr->xa.setwidth != wantPtr->xa.setwidth) {
2698 if (gotPtr->fa.size == 0.0) {
2700 * A scalable font is almost always acceptable, but the corresponding
2701 * bitmapped font would be better.
2709 * It's worse to be too large than to be too small.
2712 diff = (int) (150 * (-gotPtr->fa.size - -wantPtr->fa.size));
2715 } else if (diff < 0) {
2721 if (gotPtr->xa.charset != wantPtr->xa.charset) {
2723 const char *gotAlias, *wantAlias;
2726 gotAlias = GetEncodingAlias(gotPtr->xa.charset);
2727 wantAlias = GetEncodingAlias(wantPtr->xa.charset);
2728 if (strcmp(gotAlias, wantAlias) != 0) {
2730 for (i = 0; i < sizeof(encodingList)/sizeof(encodingList[0]); i++) {
2731 if (strcmp(gotAlias, encodingList[i]) == 0) {
2743 *---------------------------------------------------------------------------
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.
2752 * The screen font that best corresponds to the set of attributes.
2757 *---------------------------------------------------------------------------
2760 static XFontStruct *
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. */
2772 XFontStruct *fontStructPtr;
2774 if ((bestIdx[0] < 0) && (bestIdx[1] < 0)) {
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
2786 fontStructPtr = NULL;
2787 if (bestScore[1] < bestScore[0]) {
2788 char *str, *rest, buf[256];
2792 * Fill in the desired pixel size for this font.
2796 str = nameList[bestIdx[1]];
2797 for (i = 0; i < XLFD_PIXEL_SIZE; i++) {
2798 str = strchr(str + 1, '-');
2801 for (i = XLFD_PIXEL_SIZE; i < XLFD_CHARSET; i++) {
2802 rest = strchr(rest + 1, '-');
2805 sprintf(buf, "%.200s-%d-*-*-*-*-*%s", nameList[bestIdx[1]],
2806 (int)(-wantPtr->fa.size+0.5), rest);
2808 fontStructPtr = XLoadQueryFont(display, buf);
2809 bestScore[1] = INT_MAX;
2811 if (fontStructPtr == NULL) {
2812 fontStructPtr = XLoadQueryFont(display, nameList[bestIdx[0]]);
2813 if (fontStructPtr == NULL) {
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.
2819 if (bestScore[1] < INT_MAX) {
2822 return GetSystemFont(display);
2825 return fontStructPtr;
2829 *---------------------------------------------------------------------------
2833 * Absolute fallback mechanism, called when we need a font and no other
2834 * font can be found and/or instantiated.
2837 * A pointer to a font. Never NULL.
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?
2843 *---------------------------------------------------------------------------
2846 static XFontStruct *
2848 Display *display) /* Display for new XFontStruct. */
2850 XFontStruct *fontStructPtr;
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");
2859 return fontStructPtr;
2863 *---------------------------------------------------------------------------
2865 * GetFontAttributes --
2867 * Given a screen font, determine its actual attributes, which are not
2868 * necessarily the attributes that were used to construct it.
2871 * *faPtr is filled with the screen font's attributes.
2876 *---------------------------------------------------------------------------
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. */
2885 unsigned long value;
2888 if ((XGetFontProperty(fontStructPtr, XA_FONT, &value) != False) &&
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("");
2898 TkInitFontAttributes(&faPtr->fa);
2899 TkInitXLFDAttributes(&faPtr->xa);
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
2908 if (faPtr->fa.family == NULL) {
2909 faPtr->fa.family = Tk_GetUid("");
2910 faPtr->xa.foundry = Tk_GetUid("");
2911 faPtr->xa.charset = Tk_GetUid("");
2913 return IdentifySymbolEncodings(faPtr);
2917 *---------------------------------------------------------------------------
2921 * Utility function to return the array of all XLFDs on the system with
2922 * the specified face name.
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.
2931 *---------------------------------------------------------------------------
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. */
2943 sprintf(buf, "-*-%.80s-*-*-*-*-*-*-*-*-*-*-*-*", faceName);
2944 return XListFonts(display, buf, 10000, numNamesPtr);
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. */
2955 const char *const *aliases;
2958 nameList = ListFonts(display, faceName, numNamesPtr);
2959 if (nameList != NULL) {
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) {
2976 *---------------------------------------------------------------------------
2978 * IdentifySymbolEncodings --
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.
2985 * Symbol fonts are all fonts whose name appears in the symbolClass.
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.
2996 *---------------------------------------------------------------------------
3000 IdentifySymbolEncodings(
3001 FontAttributes *faPtr)
3004 const char *const *aliases;
3005 const char *const *symbolClass;
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]));
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]));
3025 *---------------------------------------------------------------------------
3027 * GetEncodingAlias --
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".
3036 * As above. If the name has no alias, the original name is returned.
3041 *---------------------------------------------------------------------------
3046 const char *name) /* The name to look up. */
3048 const EncodingAlias *aliasPtr;
3050 for (aliasPtr = encodingAliases; aliasPtr->aliasPattern != NULL; ) {
3051 if (Tcl_StringCaseMatch(name, aliasPtr->aliasPattern, 0)) {
3052 return aliasPtr->realName;
3060 *---------------------------------------------------------------------------
3062 * TkDrawAngledChars --
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!
3076 * Target drawable is updated.
3078 *---------------------------------------------------------------------------
3081 static inline XImage *
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)
3097 TkFont *fontPtr = (TkFont *) tkfont;
3101 XImage *image = NULL;
3103 (void) Tk_MeasureChars(tkfont, source, numBytes, -1, 0, &width);
3104 height = fontPtr->fm.ascent + fontPtr->fm.descent;
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,
3112 XFillRectangle(display, bitmap, bitmapGC, 0, 0, width, height);
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);
3122 image = XGetImage(display, bitmap, 0, 0, width, height, AllPlanes,
3124 Tk_FreePixmap(display, bitmap);
3127 *realWidthPtr = width;
3128 *realHeightPtr = height;
3132 static inline XImage *
3140 Pixmap bitmap = None;
3141 XImage *image = NULL;
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,
3151 XFillRectangle(display, bitmap, bitmapGC, 0, 0, width, height);
3152 XFreeGC(display, bitmapGC);
3154 image = XGetImage(display, bitmap, 0, 0, width, height, AllPlanes,
3157 *bitmapPtr = bitmap;
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. */
3180 Tk_DrawChars(display, drawable, gc, tkfont, source, numBytes, x, y);
3182 double sinA = sin(angle * PI/180.0), cosA = cos(angle * PI/180.0);
3183 int bufHeight, bufWidth, srcWidth, srcHeight, i, j, dx, dy;
3185 XImage *srcImage = GetImageOfText(display, drawable, tkfont, source,
3186 numBytes, &srcWidth, &srcHeight);
3188 enum {Q0=1,R1,Q1,R2,Q2,R3,Q3} quadrant;
3191 int ascent = ((TkFont *) tkfont)->fm.ascent;
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.
3210 } else if (angle == 90.0) {
3212 } else if (angle < 180.0) {
3214 } else if (angle == 180.0) {
3216 } else if (angle < 270.0) {
3218 } else if (angle == 270.0) {
3224 if (srcImage == NULL) {
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);
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.
3242 for (i=0 ; i<srcWidth ; i++) {
3243 for (j=0 ; j<srcHeight ; j++) {
3246 dx = ROUND16(i*cosA + j*sinA);
3247 dy = ROUND16(j*cosA + (srcWidth - i)*sinA);
3254 dx = ROUND16((i - srcWidth)*cosA + j*sinA);
3255 dy = ROUND16((srcWidth-i)*sinA + (j-srcHeight)*cosA);
3262 dx = ROUND16((i-srcWidth)*cosA + (j-srcHeight)*sinA);
3263 dy = ROUND16((j - srcHeight)*cosA - i*sinA);
3270 dx = ROUND16(i*cosA + (j - srcHeight)*sinA);
3271 dy = ROUND16(j*cosA - i*sinA);
3274 if (dx < 0 || dy < 0 || dx >= bufWidth || dy >= bufHeight) {
3277 XPutPixel(dstImage, dx, dy,
3278 XGetPixel(dstImage,dx,dy) | XGetPixel(srcImage,i,j));
3281 XDestroyImage(srcImage);
3284 * Schlep the data back to the Xserver.
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,
3292 XPutImage(display, buf, bwgc, dstImage, 0,0, 0,0, bufWidth,bufHeight);
3293 XFreeGC(display, bwgc);
3294 XDestroyImage(dstImage);
3297 * Calculate where we want to draw the text.
3303 dy = y - srcWidth*sinA;
3310 dx = x + srcWidth*cosA;
3311 dy = y + srcHeight*cosA - srcWidth*sinA;
3318 dx = x + srcWidth*cosA + srcHeight*sinA;
3319 dy = y + srcHeight*cosA;
3326 dx = x + srcHeight*sinA;
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
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.
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,
3352 XCopyGC(display, gc, GCForeground, cpgc);
3353 XFillRectangle(display, drawable, cpgc, dx, dy, bufWidth,
3355 XFreeGC(display, cpgc);
3357 Tk_FreePixmap(display, buf);