📄 tkunixfont.c
字号:
/* * tkUnixFont.c -- * * Contains the Unix implementation of the platform-independant * font package interface. * * Copyright (c) 1996 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tkUnixFont.c 1.16 97/10/23 12:47:53 */ #include "tkPort.h"#include "tkInt.h"#include "tkUnixInt.h"#include "tkFont.h"#ifndef ABS#define ABS(n) (((n) < 0) ? -(n) : (n))#endif/* * The following structure represents Unix's implementation of a font. */ typedef struct UnixFont { TkFont font; /* Stuff used by generic font package. Must * be first in structure. */ Display *display; /* The display to which font belongs. */ XFontStruct *fontStructPtr; /* X information about font. */ char types[256]; /* Array giving types of all characters in * the font, used when displaying control * characters. See below for definition. */ int widths[256]; /* Array giving widths of all possible * characters in the font. */ int underlinePos; /* Offset from baseline to origin of * underline bar (used for simulating a native * underlined font). */ int barHeight; /* Height of underline or overstrike bar * (used for simulating a native underlined or * strikeout font). */} UnixFont;/* * Possible values for entries in the "types" field in a UnixFont structure, * which classifies the types of all characters in the given font. This * information is used when measuring and displaying characters. * * NORMAL: Standard character. * REPLACE: This character doesn't print: instead of * displaying character, display a replacement * sequence like "\n" (for those characters where * ANSI C defines such a sequence) or a sequence * of the form "\xdd" where dd is the hex equivalent * of the character. * SKIP: Don't display anything for this character. This * is only used where the font doesn't contain * all the characters needed to generate * replacement sequences. */ #define NORMAL 0#define REPLACE 1#define SKIP 2/* * Characters used when displaying control sequences. */static char hexChars[] = "0123456789abcdefxtnvr\\";/* * The following table maps some control characters to sequences like '\n' * rather than '\x10'. A zero entry in the table means no such mapping * exists, and the table only maps characters less than 0x10. */static char mapChars[] = { 0, 0, 0, 0, 0, 0, 0, 'a', 'b', 't', 'n', 'v', 'f', 'r', 0};static UnixFont * AllocFont _ANSI_ARGS_((TkFont *tkFontPtr, Tk_Window tkwin, XFontStruct *fontStructPtr, CONST char *fontName));static void DrawChars _ANSI_ARGS_((Display *display, Drawable drawable, GC gc, UnixFont *fontPtr, CONST char *source, int numChars, int x, int y));static int GetControlCharSubst _ANSI_ARGS_((int c, char buf[4]));/* *--------------------------------------------------------------------------- * * TkpGetNativeFont -- * * Map a platform-specific native font name to a TkFont. * * Results: * The return value is a pointer to a TkFont that represents the * native font. If a native font by the given name could not be * found, the return value is NULL. * * Every call to this procedure returns a new TkFont structure, * even if the name has already been seen before. The caller should * call TkpDeleteFont() when the font is no longer needed. * * The caller is responsible for initializing the memory associated * with the generic TkFont when this function returns and releasing * the contents of the generic TkFont before calling TkpDeleteFont(). * * Side effects: * None. * *--------------------------------------------------------------------------- */TkFont *TkpGetNativeFont(tkwin, name) Tk_Window tkwin; /* For display where font will be used. */ CONST char *name; /* Platform-specific font name. */{ XFontStruct *fontStructPtr; fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), name); if (fontStructPtr == NULL) { return NULL; } return (TkFont *) AllocFont(NULL, tkwin, fontStructPtr, name);}/* *--------------------------------------------------------------------------- * * TkpGetFontFromAttributes -- * * Given a desired set of attributes for a font, find a font with * the closest matching attributes. * * Results: * The return value is a pointer to a TkFont that represents the * font with the desired attributes. If a font with the desired * attributes could not be constructed, some other font will be * substituted automatically. * * Every call to this procedure returns a new TkFont structure, * even if the specified attributes have already been seen before. * The caller should call TkpDeleteFont() to free the platform- * specific data when the font is no longer needed. * * The caller is responsible for initializing the memory associated * with the generic TkFont when this function returns and releasing * the contents of the generic TkFont before calling TkpDeleteFont(). * * Side effects: * None. * *--------------------------------------------------------------------------- */TkFont *TkpGetFontFromAttributes(tkFontPtr, tkwin, faPtr) TkFont *tkFontPtr; /* If non-NULL, store the information in * this existing TkFont structure, rather than * allocating a new structure to hold the * font; the existing contents of the font * will be released. If NULL, a new TkFont * structure is allocated. */ Tk_Window tkwin; /* For display where font will be used. */ CONST TkFontAttributes *faPtr; /* Set of attributes to match. */{ int numNames, score, i, scaleable, pixelsize, xaPixelsize; int bestIdx, bestScore, bestScaleableIdx, bestScaleableScore; TkXLFDAttributes xa; char buf[256]; UnixFont *fontPtr; char **nameList; XFontStruct *fontStructPtr; CONST char *fmt, *family; double d; family = faPtr->family; if (family == NULL) { family = "*"; } pixelsize = -faPtr->pointsize; if (pixelsize < 0) { d = -pixelsize * 25.4 / 72; d *= WidthOfScreen(Tk_Screen(tkwin)); d /= WidthMMOfScreen(Tk_Screen(tkwin)); d += 0.5; pixelsize = (int) d; } /* * Replace the standard Windows and Mac family names with the names that * X likes. */ if ((strcasecmp("Times New Roman", family) == 0) || (strcasecmp("New York", family) == 0)) { family = "Times"; } else if ((strcasecmp("Courier New", family) == 0) || (strcasecmp("Monaco", family) == 0)) { family = "Courier"; } else if ((strcasecmp("Arial", family) == 0) || (strcasecmp("Geneva", family) == 0)) { family = "Helvetica"; } /* * First try for the Q&D exact match. */#if 0 sprintf(buf, "-*-%.200s-%s-%c-normal-*-*-%d-*-*-*-*-iso8859-1", family, ((faPtr->weight > TK_FW_NORMAL) ? "bold" : "medium"), ((faPtr->slant == TK_FS_ROMAN) ? 'r' : (faPtr->slant == TK_FS_ITALIC) ? 'i' : 'o'), faPtr->pointsize * 10); fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), buf);#else fontStructPtr = NULL;#endif if (fontStructPtr != NULL) { goto end; } /* * Couldn't find exact match. Now fall back to other available * physical fonts. */ fmt = "-*-%.240s-*-*-*-*-*-*-*-*-*-*-*-*"; sprintf(buf, fmt, family); nameList = XListFonts(Tk_Display(tkwin), buf, 10000, &numNames); if (numNames == 0) { /* * Try getting some system font. */ sprintf(buf, fmt, "fixed"); nameList = XListFonts(Tk_Display(tkwin), buf, 10000, &numNames); if (numNames == 0) { getsystem: fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), "fixed"); if (fontStructPtr == NULL) { fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), "*"); if (fontStructPtr == NULL) { panic("TkpGetFontFromAttributes: cannot get any font"); } } goto end; } } /* * Inspect each of the XLFDs and pick the one that most closely * matches the desired attributes. */ bestIdx = 0; bestScore = INT_MAX; bestScaleableIdx = 0; bestScaleableScore = INT_MAX; for (i = 0; i < numNames; i++) { score = 0; scaleable = 0; if (TkParseXLFD(nameList[i], &xa) != TCL_OK) { continue; } xaPixelsize = -xa.fa.pointsize; /* * Since most people used to use -adobe-* in their XLFDs, * preserve the preference for "adobe" foundry. Otherwise * some applications looks may change slightly if another foundry * is chosen. */ if (strcasecmp(xa.foundry, "adobe") != 0) { score += 3000; } if (xa.fa.pointsize == 0) { /* * A scaleable font is almost always acceptable, but the * corresponding bitmapped font would be better. */ score += 10; scaleable = 1; } else { /* * A font that is too small is better than one that is too * big. */ if (xaPixelsize > pixelsize) { score += (xaPixelsize - pixelsize) * 120; } else { score += (pixelsize - xaPixelsize) * 100; } } score += ABS(xa.fa.weight - faPtr->weight) * 30; score += ABS(xa.fa.slant - faPtr->slant) * 25; if (xa.slant == TK_FS_OBLIQUE) { /* * Italic fonts are preferred over oblique. */ score += 4; } if (xa.setwidth != TK_SW_NORMAL) { /* * The normal setwidth is highly preferred. */ score += 2000; } if (xa.charset == TK_CS_OTHER) { /* * The standard character set is highly preferred over * foreign languages charsets (because we don't support * other languages yet). */ score += 11000; } if ((xa.charset == TK_CS_NORMAL) && (xa.encoding != 1)) { /* * The '1' encoding for the characters above 0x7f is highly * preferred over the other encodings. */ score += 8000; } if (scaleable) { if (score < bestScaleableScore) { bestScaleableIdx = i; bestScaleableScore = score; } } else { if (score < bestScore) { bestIdx = i; bestScore = score; } } if (score == 0) { break; } } /* * Now we know which is the closest matching scaleable font and the * closest matching bitmapped font. If the scaleable font was a * better match, try getting the scaleable font; however, if the * scalable font was not actually available in the desired * pointsize, fall back to the closest bitmapped font. */ fontStructPtr = NULL; if (bestScaleableScore < bestScore) { char *str, *rest; /* * Fill in the desired pointsize info for this font. */ tryscale: str = nameList[bestScaleableIdx]; for (i = 0; i < XLFD_PIXEL_SIZE - 1; i++) { str = strchr(str + 1, '-'); } rest = str; for (i = XLFD_PIXEL_SIZE - 1; i < XLFD_REGISTRY; i++) { rest = strchr(rest + 1, '-'); } *str = '\0'; sprintf(buf, "%.240s-*-%d-*-*-*-*-*%s", nameList[bestScaleableIdx], pixelsize, rest); *str = '-'; fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), buf); bestScaleableScore = INT_MAX; } if (fontStructPtr == NULL) { strcpy(buf, nameList[bestIdx]); fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), buf); if (fontStructPtr == NULL) { /* * This shouldn't happen because the font name is one of the * names that X gave us to use, but it does anyhow. */ if (bestScaleableScore < INT_MAX) { goto tryscale; } else { XFreeFontNames(nameList); goto getsystem; } } } XFreeFontNames(nameList); end: fontPtr = AllocFont(tkFontPtr, tkwin, fontStructPtr, buf); fontPtr->font.fa.underline = faPtr->underline; fontPtr->font.fa.overstrike = faPtr->overstrike; return (TkFont *) fontPtr;}/* *--------------------------------------------------------------------------- * * TkpDeleteFont -- * * Called to release a font allocated by TkpGetNativeFont() or * TkpGetFontFromAttributes(). The caller should have already * released the fields of the TkFont that are used exclusively by * the generic TkFont code. * * Results: * None. * * Side effects: * TkFont is deallocated. * *--------------------------------------------------------------------------- */voidTkpDeleteFont(tkFontPtr) TkFont *tkFontPtr; /* Token of font to be deleted. */{ UnixFont *fontPtr; fontPtr = (UnixFont *) tkFontPtr; XFreeFont(fontPtr->display, fontPtr->fontStructPtr); ckfree((char *) fontPtr);}/* *--------------------------------------------------------------------------- * * TkpGetFontFamilies -- * * Return information about the font families that are available * on the display of the given window. * * Results: * interp->result is modified to hold a list of all the available * font families. * * Side effects: * None. * *--------------------------------------------------------------------------- */ voidTkpGetFontFamilies(interp, tkwin) Tcl_Interp *interp; Tk_Window tkwin;{ int i, new, numNames; char *family, *end, *p; Tcl_HashTable familyTable; Tcl_HashEntry *hPtr; Tcl_HashSearch search; char **nameList; Tcl_InitHashTable(&familyTable, TCL_STRING_KEYS); nameList = XListFonts(Tk_Display(tkwin), "*", 10000, &numNames); for (i = 0; i < numNames; i++) { if (nameList[i][0] != '-') { continue; } family = strchr(nameList[i] + 1, '-'); if (family == NULL) { continue; } family++; end = strchr(family, '-'); if (end == NULL) { continue; } *end = '\0'; for (p = family; *p != '\0'; p++) { if (isupper(UCHAR(*p))) { *p = tolower(UCHAR(*p));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -