summaryrefslogtreecommitdiffstats
path: root/tk8.6/unix/tkUnixFont.c
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2016-12-21 22:13:18 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2016-12-21 22:13:18 (GMT)
commit07e464099b99459d0a37757771791598ef3395d9 (patch)
tree4ba7d8aad13735e52f59bdce7ca5ba3151ebd7e3 /tk8.6/unix/tkUnixFont.c
parentdeb3650e37f26f651f280e480c4df3d7dde87bae (diff)
downloadblt-07e464099b99459d0a37757771791598ef3395d9.zip
blt-07e464099b99459d0a37757771791598ef3395d9.tar.gz
blt-07e464099b99459d0a37757771791598ef3395d9.tar.bz2
new subtree for tcl/tk
Diffstat (limited to 'tk8.6/unix/tkUnixFont.c')
-rw-r--r--tk8.6/unix/tkUnixFont.c3323
1 files changed, 0 insertions, 3323 deletions
diff --git a/tk8.6/unix/tkUnixFont.c b/tk8.6/unix/tkUnixFont.c
deleted file mode 100644
index a4998aa..0000000
--- a/tk8.6/unix/tkUnixFont.c
+++ /dev/null
@@ -1,3323 +0,0 @@
-/*
- * tkUnixFont.c --
- *
- * Contains the Unix implementation of the platform-independent font
- * package interface.
- *
- * Copyright (c) 1996-1997 Sun Microsystems, Inc.
- *
- * See the file "license.terms" for information on usage and redistribution of
- * this file, and for a DISCLAIMER OF ALL WARRANTIES.
- */
-
-#include "tkUnixInt.h"
-#include "tkFont.h"
-#include <netinet/in.h> /* for htons() prototype */
-#include <arpa/inet.h> /* inet_ntoa() */
-
-/*
- * The preferred font encodings.
- */
-
-static const char *const encodingList[] = {
- "iso8859-1", "jis0208", "jis0212", NULL
-};
-
-/*
- * The following structure represents a font family. It is assumed that all
- * screen fonts constructed from the same "font family" share certain
- * properties; all screen fonts with the same "font family" point to a shared
- * instance of this structure. The most important shared property is the
- * character existence metrics, used to determine if a screen font can display
- * a given Unicode character.
- *
- * Under Unix, there are three attributes that uniquely identify a "font
- * family": the foundry, face name, and charset.
- */
-
-#define FONTMAP_SHIFT 10
-
-#define FONTMAP_PAGES (1 << (sizeof(Tcl_UniChar)*8 - FONTMAP_SHIFT))
-#define FONTMAP_BITSPERPAGE (1 << FONTMAP_SHIFT)
-
-typedef struct FontFamily {
- struct FontFamily *nextPtr; /* Next in list of all known font families. */
- int refCount; /* How many SubFonts are referring to this
- * FontFamily. When the refCount drops to
- * zero, this FontFamily may be freed. */
- /*
- * Key.
- */
-
- Tk_Uid foundry; /* Foundry key for this FontFamily. */
- Tk_Uid faceName; /* Face name key for this FontFamily. */
- Tcl_Encoding encoding; /* Encoding key for this FontFamily. */
-
- /*
- * Derived properties.
- */
-
- int isTwoByteFont; /* 1 if this is a double-byte font, 0
- * otherwise. */
- char *fontMap[FONTMAP_PAGES];
- /* Two-level sparse table used to determine
- * quickly if the specified character exists.
- * As characters are encountered, more pages
- * in this table are dynamically alloced. The
- * contents of each page is a bitmask
- * consisting of FONTMAP_BITSPERPAGE bits,
- * representing whether this font can be used
- * to display the given character at the
- * corresponding bit position. The high bits
- * of the character are used to pick which
- * page of the table is used. */
-} FontFamily;
-
-/*
- * The following structure encapsulates an individual screen font. A font
- * object is made up of however many SubFonts are necessary to display a
- * stream of multilingual characters.
- */
-
-typedef struct SubFont {
- char **fontMap; /* Pointer to font map from the FontFamily,
- * cached here to save a dereference. */
- XFontStruct *fontStructPtr; /* The specific screen font that will be used
- * when displaying/measuring chars belonging
- * to the FontFamily. */
- FontFamily *familyPtr; /* The FontFamily for this SubFont. */
-} SubFont;
-
-/*
- * The following structure represents Unix's implementation of a font object.
- */
-
-#define SUBFONT_SPACE 3
-#define BASE_CHARS 256
-
-typedef struct UnixFont {
- TkFont font; /* Stuff used by generic font package. Must be
- * first in structure. */
- SubFont staticSubFonts[SUBFONT_SPACE];
- /* Builtin space for a limited number of
- * SubFonts. */
- int numSubFonts; /* Length of following array. */
- SubFont *subFontArray; /* Array of SubFonts that have been loaded in
- * order to draw/measure all the characters
- * encountered by this font so far. All fonts
- * start off with one SubFont initialized by
- * AllocFont() from the original set of font
- * attributes. Usually points to
- * staticSubFonts, but may point to malloced
- * space if there are lots of SubFonts. */
- SubFont controlSubFont; /* Font to use to display control-character
- * expansions. */
-
- Display *display; /* Display that owns font. */
- int pixelSize; /* Original pixel size used when font was
- * constructed. */
- TkXLFDAttributes xa; /* Additional attributes that specify the
- * preferred foundry and encoding to use when
- * constructing additional SubFonts. */
- int widths[BASE_CHARS]; /* Widths of first 256 chars in the base font,
- * for handling common case. */
- int underlinePos; /* Offset from baseline to origin of underline
- * bar (used when drawing underlined font)
- * (pixels). */
- int barHeight; /* Height of underline or overstrike bar (used
- * when drawing underlined or strikeout font)
- * (pixels). */
-} UnixFont;
-
-/*
- * The following structure and definition is used to keep track of the
- * alternative names for various encodings. Asking for an encoding that
- * matches one of the alias patterns will result in actually getting the
- * encoding by its real name.
- */
-
-typedef struct EncodingAlias {
- const char *realName; /* The real name of the encoding to load if
- * the provided name matched the pattern. */
- const char *aliasPattern; /* Pattern for encoding name, of the form that
- * is acceptable to Tcl_StringMatch. */
-} EncodingAlias;
-
-/*
- * Just some utility structures used for passing around values in helper
- * functions.
- */
-
-typedef struct FontAttributes {
- TkFontAttributes fa;
- TkXLFDAttributes xa;
-} FontAttributes;
-
-typedef struct ThreadSpecificData {
- FontFamily *fontFamilyList; /* The list of font families that are
- * currently loaded. As screen fonts are
- * loaded, this list grows to hold information
- * about what characters exist in each font
- * family. */
- FontFamily controlFamily; /* FontFamily used to handle control character
- * expansions. The encoding of this FontFamily
- * converts UTF-8 to backslashed escape
- * sequences. */
-} ThreadSpecificData;
-static Tcl_ThreadDataKey dataKey;
-
-/*
- * The set of builtin encoding alises to convert the XLFD names for the
- * encodings into the names expected by the Tcl encoding package.
- */
-
-static EncodingAlias encodingAliases[] = {
- {"gb2312-raw", "gb2312*"},
- {"big5", "big5*"},
- {"cns11643-1", "cns11643*-1"},
- {"cns11643-1", "cns11643*.1-0"},
- {"cns11643-2", "cns11643*-2"},
- {"cns11643-2", "cns11643*.2-0"},
- {"jis0201", "jisx0201*"},
- {"jis0201", "jisx0202*"},
- {"jis0208", "jisc6226*"},
- {"jis0208", "jisx0208*"},
- {"jis0212", "jisx0212*"},
- {"tis620", "tis620*"},
- {"ksc5601", "ksc5601*"},
- {"dingbats", "*dingbats"},
-#ifdef WORDS_BIGENDIAN
- {"unicode", "iso10646-1"},
-#else
- /*
- * ucs-2be is needed if native order isn't BE.
- */
- {"ucs-2be", "iso10646-1"},
-#endif
- {NULL, NULL}
-};
-
-/*
- * Functions used only in this file.
- */
-
-static void FontPkgCleanup(ClientData clientData);
-static FontFamily * AllocFontFamily(Display *display,
- XFontStruct *fontStructPtr, int base);
-static SubFont * CanUseFallback(UnixFont *fontPtr,
- const char *fallbackName, int ch,
- SubFont **fixSubFontPtrPtr);
-static SubFont * CanUseFallbackWithAliases(UnixFont *fontPtr,
- const char *fallbackName, int ch,
- Tcl_DString *nameTriedPtr,
- SubFont **fixSubFontPtrPtr);
-static int ControlUtfProc(ClientData clientData, const char *src,
- int srcLen, int flags, Tcl_EncodingState*statePtr,
- char *dst, int dstLen, int *srcReadPtr,
- int *dstWrotePtr, int *dstCharsPtr);
-static XFontStruct * CreateClosestFont(Tk_Window tkwin,
- const TkFontAttributes *faPtr,
- const TkXLFDAttributes *xaPtr);
-static SubFont * FindSubFontForChar(UnixFont *fontPtr, int ch,
- SubFont **fixSubFontPtrPtr);
-static void FontMapInsert(SubFont *subFontPtr, int ch);
-static void FontMapLoadPage(SubFont *subFontPtr, int row);
-static int FontMapLookup(SubFont *subFontPtr, int ch);
-static void FreeFontFamily(FontFamily *afPtr);
-static const char * GetEncodingAlias(const char *name);
-static int GetFontAttributes(Display *display,
- XFontStruct *fontStructPtr, FontAttributes *faPtr);
-static XFontStruct * GetScreenFont(Display *display,
- FontAttributes *wantPtr, char **nameList,
- int bestIdx[], unsigned bestScore[]);
-static XFontStruct * GetSystemFont(Display *display);
-static int IdentifySymbolEncodings(FontAttributes *faPtr);
-static void InitFont(Tk_Window tkwin, XFontStruct *fontStructPtr,
- UnixFont *fontPtr);
-static void InitSubFont(Display *display,
- XFontStruct *fontStructPtr, int base,
- SubFont *subFontPtr);
-static char ** ListFonts(Display *display, const char *faceName,
- int *numNamesPtr);
-static char ** ListFontOrAlias(Display *display, const char*faceName,
- int *numNamesPtr);
-static unsigned RankAttributes(FontAttributes *wantPtr,
- FontAttributes *gotPtr);
-static void ReleaseFont(UnixFont *fontPtr);
-static void ReleaseSubFont(Display *display, SubFont *subFontPtr);
-static int SeenName(const char *name, Tcl_DString *dsPtr);
-#ifndef WORDS_BIGENDIAN
-static int Ucs2beToUtfProc(ClientData clientData, const char*src,
- int srcLen, int flags, Tcl_EncodingState*statePtr,
- char *dst, int dstLen, int *srcReadPtr,
- int *dstWrotePtr, int *dstCharsPtr);
-static int UtfToUcs2beProc(ClientData clientData, const char*src,
- int srcLen, int flags, Tcl_EncodingState*statePtr,
- char *dst, int dstLen, int *srcReadPtr,
- int *dstWrotePtr, int *dstCharsPtr);
-#endif
-
-/*
- *-------------------------------------------------------------------------
- *
- * FontPkgCleanup --
- *
- * This function is called when an application is created. It initializes
- * all the structures that are used by the platform-dependent code on a
- * per application basis.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Releases thread-specific resources used by font pkg.
- *
- *-------------------------------------------------------------------------
- */
-
-static void
-FontPkgCleanup(
- ClientData clientData)
-{
- ThreadSpecificData *tsdPtr =
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
-
- if (tsdPtr->controlFamily.encoding != NULL) {
- FontFamily *familyPtr = &tsdPtr->controlFamily;
- int i;
-
- Tcl_FreeEncoding(familyPtr->encoding);
- for (i = 0; i < FONTMAP_PAGES; i++) {
- if (familyPtr->fontMap[i] != NULL) {
- ckfree(familyPtr->fontMap[i]);
- }
- }
- tsdPtr->controlFamily.encoding = NULL;
- }
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * TkpFontPkgInit --
- *
- * This function is called when an application is created. It initializes
- * all the structures that are used by the platform-dependent code on a
- * per application basis.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-------------------------------------------------------------------------
- */
-
-void
-TkpFontPkgInit(
- TkMainInfo *mainPtr) /* The application being created. */
-{
- ThreadSpecificData *tsdPtr =
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- Tcl_EncodingType type;
- SubFont dummy;
- int i;
-
- if (tsdPtr->controlFamily.encoding == NULL) {
- type.encodingName = "X11ControlChars";
- type.toUtfProc = ControlUtfProc;
- type.fromUtfProc = ControlUtfProc;
- type.freeProc = NULL;
- type.clientData = NULL;
- type.nullSize = 0;
-
- tsdPtr->controlFamily.refCount = 2;
- tsdPtr->controlFamily.encoding = Tcl_CreateEncoding(&type);
- tsdPtr->controlFamily.isTwoByteFont = 0;
-
- dummy.familyPtr = &tsdPtr->controlFamily;
- dummy.fontMap = tsdPtr->controlFamily.fontMap;
- for (i = 0x00; i < 0x20; i++) {
- FontMapInsert(&dummy, i);
- FontMapInsert(&dummy, i + 0x80);
- }
-
-#ifndef WORDS_BIGENDIAN
- /*
- * UCS-2BE is unicode (UCS-2) in big-endian format. Define this if
- * native order isn't BE. It is used in iso10646 fonts.
- */
-
- type.encodingName = "ucs-2be";
- type.toUtfProc = Ucs2beToUtfProc;
- type.fromUtfProc = UtfToUcs2beProc;
- type.freeProc = NULL;
- type.clientData = NULL;
- type.nullSize = 2;
- Tcl_CreateEncoding(&type);
-#endif
- Tcl_CreateThreadExitHandler(FontPkgCleanup, NULL);
- }
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * ControlUtfProc --
- *
- * Convert from UTF-8 into the ASCII expansion of a control character.
- *
- * Results:
- * Returns TCL_OK if conversion was successful.
- *
- * Side effects:
- * None.
- *
- *-------------------------------------------------------------------------
- */
-
-static int
-ControlUtfProc(
- ClientData clientData, /* Not used. */
- const char *src, /* Source string in UTF-8. */
- int srcLen, /* Source string length in bytes. */
- int flags, /* Conversion control flags. */
- Tcl_EncodingState *statePtr,/* Place for conversion routine to store state
- * information used during a piecewise
- * conversion. Contents of statePtr are
- * initialized and/or reset by conversion
- * routine under control of flags argument. */
- char *dst, /* Output buffer in which converted string is
- * stored. */
- int dstLen, /* The maximum length of output buffer in
- * bytes. */
- int *srcReadPtr, /* Filled with the number of bytes from the
- * source string that were converted. This may
- * be less than the original source length if
- * there was a problem converting some source
- * characters. */
- int *dstWrotePtr, /* Filled with the number of bytes that were
- * stored in the output buffer as a result of
- * the conversion. */
- int *dstCharsPtr) /* Filled with the number of characters that
- * correspond to the bytes stored in the
- * output buffer. */
-{
- const char *srcStart, *srcEnd;
- char *dstStart, *dstEnd;
- Tcl_UniChar ch;
- int result;
- static char hexChars[] = "0123456789abcdef";
- static char mapChars[] = {
- 0, 0, 0, 0, 0, 0, 0,
- 'a', 'b', 't', 'n', 'v', 'f', 'r'
- };
-
- result = TCL_OK;
-
- srcStart = src;
- srcEnd = src + srcLen;
-
- dstStart = dst;
- dstEnd = dst + dstLen - 6;
-
- for ( ; src < srcEnd; ) {
- if (dst > dstEnd) {
- result = TCL_CONVERT_NOSPACE;
- break;
- }
- src += Tcl_UtfToUniChar(src, &ch);
- dst[0] = '\\';
- if ((ch < sizeof(mapChars)) && (mapChars[ch] != 0)) {
- dst[1] = mapChars[ch];
- dst += 2;
- } else if (ch < 256) {
- dst[1] = 'x';
- dst[2] = hexChars[(ch >> 4) & 0xf];
- dst[3] = hexChars[ch & 0xf];
- dst += 4;
- } else {
- dst[1] = 'u';
- dst[2] = hexChars[(ch >> 12) & 0xf];
- dst[3] = hexChars[(ch >> 8) & 0xf];
- dst[4] = hexChars[(ch >> 4) & 0xf];
- dst[5] = hexChars[ch & 0xf];
- dst += 6;
- }
- }
- *srcReadPtr = src - srcStart;
- *dstWrotePtr = dst - dstStart;
- *dstCharsPtr = dst - dstStart;
- return result;
-}
-
-#ifndef WORDS_BIGENDIAN
-/*
- *-------------------------------------------------------------------------
- *
- * Ucs2beToUtfProc --
- *
- * Convert from UCS-2BE (big-endian 16-bit Unicode) to UTF-8.
- * This is only defined on LE machines.
- *
- * Results:
- * Returns TCL_OK if conversion was successful.
- *
- * Side effects:
- * None.
- *
- *-------------------------------------------------------------------------
- */
-
-static int
-Ucs2beToUtfProc(
- ClientData clientData, /* Not used. */
- const char *src, /* Source string in Unicode. */
- int srcLen, /* Source string length in bytes. */
- int flags, /* Conversion control flags. */
- Tcl_EncodingState *statePtr,/* Place for conversion routine to store state
- * information used during a piecewise
- * conversion. Contents of statePtr are
- * initialized and/or reset by conversion
- * routine under control of flags argument. */
- char *dst, /* Output buffer in which converted string is
- * stored. */
- int dstLen, /* The maximum length of output buffer in
- * bytes. */
- int *srcReadPtr, /* Filled with the number of bytes from the
- * source string that were converted. This may
- * be less than the original source length if
- * there was a problem converting some source
- * characters. */
- int *dstWrotePtr, /* Filled with the number of bytes that were
- * stored in the output buffer as a result of
- * the conversion. */
- int *dstCharsPtr) /* Filled with the number of characters that
- * correspond to the bytes stored in the
- * output buffer. */
-{
- const char *srcStart, *srcEnd;
- char *dstEnd, *dstStart;
- int result, numChars;
-
- result = TCL_OK;
-
- /* check alignment with ucs-2 (2 == sizeof(UCS-2)) */
- if ((srcLen % 2) != 0) {
- result = TCL_CONVERT_MULTIBYTE;
- srcLen--;
- }
-
- srcStart = src;
- srcEnd = src + srcLen;
-
- dstStart = dst;
- dstEnd = dst + dstLen - TCL_UTF_MAX;
-
- for (numChars = 0; src < srcEnd; numChars++) {
- if (dst > dstEnd) {
- result = TCL_CONVERT_NOSPACE;
- break;
- }
-
- /*
- * Need to swap byte-order on little-endian machines (x86) for
- * UCS-2BE. We know this is an LE->BE swap.
- */
-
- dst += Tcl_UniCharToUtf(htons(*((short *)src)), dst);
- src += 2 /* sizeof(UCS-2) */;
- }
-
- *srcReadPtr = src - srcStart;
- *dstWrotePtr = dst - dstStart;
- *dstCharsPtr = numChars;
- return result;
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * UtfToUcs2beProc --
- *
- * Convert from UTF-8 to UCS-2BE (fixed 2-byte encoding).
- *
- * Results:
- * Returns TCL_OK if conversion was successful.
- *
- * Side effects:
- * None.
- *
- *-------------------------------------------------------------------------
- */
-
-static int
-UtfToUcs2beProc(
- ClientData clientData, /* TableEncodingData that specifies
- * encoding. */
- const char *src, /* Source string in UTF-8. */
- int srcLen, /* Source string length in bytes. */
- int flags, /* Conversion control flags. */
- Tcl_EncodingState *statePtr,/* Place for conversion routine to store state
- * information used during a piecewise
- * conversion. Contents of statePtr are
- * initialized and/or reset by conversion
- * routine under control of flags argument. */
- char *dst, /* Output buffer in which converted string is
- * stored. */
- int dstLen, /* The maximum length of output buffer in
- * bytes. */
- int *srcReadPtr, /* Filled with the number of bytes from the
- * source string that were converted. This may
- * be less than the original source length if
- * there was a problem converting some source
- * characters. */
- int *dstWrotePtr, /* Filled with the number of bytes that were
- * stored in the output buffer as a result of
- * the conversion. */
- int *dstCharsPtr) /* Filled with the number of characters that
- * correspond to the bytes stored in the
- * output buffer. */
-{
- const char *srcStart, *srcEnd, *srcClose, *dstStart, *dstEnd;
- int result, numChars;
- Tcl_UniChar ch;
-
- srcStart = src;
- srcEnd = src + srcLen;
- srcClose = srcEnd;
- if (!(flags & TCL_ENCODING_END)) {
- srcClose -= TCL_UTF_MAX;
- }
-
- dstStart = dst;
- dstEnd = dst + dstLen - 2 /* sizeof(UCS-2) */;
-
- result = TCL_OK;
- for (numChars = 0; src < srcEnd; numChars++) {
- if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) {
- /*
- * If there is more string to follow, this will ensure that the
- * last UTF-8 character in the source buffer hasn't been cut off.
- */
-
- result = TCL_CONVERT_MULTIBYTE;
- break;
- }
- if (dst > dstEnd) {
- result = TCL_CONVERT_NOSPACE;
- break;
- }
- src += Tcl_UtfToUniChar(src, &ch);
-
- /*
- * Ensure big-endianness (store big bits first).
- * XXX: This hard-codes the assumed size of Tcl_UniChar as 2. Make
- * sure to work in char* for Tcl_UtfToUniChar alignment. [Bug 1122671]
- */
-
- *dst++ = (ch >> 8);
- *dst++ = (ch & 0xFF);
- }
- *srcReadPtr = src - srcStart;
- *dstWrotePtr = dst - dstStart;
- *dstCharsPtr = numChars;
- return result;
-}
-#endif /* WORDS_BIGENDIAN */
-
-/*
- *---------------------------------------------------------------------------
- *
- * 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 function 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:
- * Memory allocated.
- *
- *---------------------------------------------------------------------------
- */
-
-TkFont *
-TkpGetNativeFont(
- Tk_Window tkwin, /* For display where font will be used. */
- const char *name) /* Platform-specific font name. */
-{
- UnixFont *fontPtr;
- XFontStruct *fontStructPtr;
- FontAttributes fa;
- const char *p;
- int hasSpace, dashes, hasWild;
-
- /*
- * The behavior of X when given a name that isn't an XLFD is unspecified.
- * For example, Exceed 6 returns a valid font for any random string. This
- * is awkward since system names have higher priority than the other Tk
- * font syntaxes. So, we need to perform a quick sanity check on the name
- * and fail if it looks suspicious. We fail if the name:
- * - contains a space immediately before a dash
- * - contains a space, but no '*' characters and fewer than 14 dashes
- */
-
- hasSpace = dashes = hasWild = 0;
- for (p = name; *p != '\0'; p++) {
- if (*p == ' ') {
- if (p[1] == '-') {
- return NULL;
- }
- hasSpace = 1;
- } else if (*p == '-') {
- dashes++;
- } else if (*p == '*') {
- hasWild = 1;
- }
- }
- if ((dashes < 14) && !hasWild && hasSpace) {
- return NULL;
- }
-
- fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), name);
- if (fontStructPtr == NULL) {
- /*
- * Handle all names that look like XLFDs here. Otherwise, when
- * TkpGetFontFromAttributes is called from generic code, any foundry
- * or encoding information specified in the XLFD will have been parsed
- * out and lost. But make sure we don't have an "-option value" string
- * since TkFontParseXLFD would return a false success when attempting
- * to parse it.
- */
-
- if (name[0] == '-') {
- if (name[1] != '*') {
- char *dash;
-
- dash = strchr(name + 1, '-');
- if ((dash == NULL) || (isspace(UCHAR(dash[-1])))) {
- return NULL;
- }
- }
- } else if (name[0] != '*') {
- return NULL;
- }
- if (TkFontParseXLFD(name, &fa.fa, &fa.xa) != TCL_OK) {
- return NULL;
- }
- fontStructPtr = CreateClosestFont(tkwin, &fa.fa, &fa.xa);
- }
- fontPtr = ckalloc(sizeof(UnixFont));
- InitFont(tkwin, fontStructPtr, fontPtr);
-
- return (TkFont *) fontPtr;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * 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 function 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:
- * Memory allocated.
- *
- *---------------------------------------------------------------------------
- */
-
-TkFont *
-TkpGetFontFromAttributes(
- 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. */
-{
- UnixFont *fontPtr;
- TkXLFDAttributes xa;
- XFontStruct *fontStructPtr;
-
- TkInitXLFDAttributes(&xa);
- fontStructPtr = CreateClosestFont(tkwin, faPtr, &xa);
-
- fontPtr = (UnixFont *) tkFontPtr;
- if (fontPtr == NULL) {
- fontPtr = ckalloc(sizeof(UnixFont));
- } else {
- ReleaseFont(fontPtr);
- }
- InitFont(tkwin, fontStructPtr, fontPtr);
-
- 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.
- *
- *---------------------------------------------------------------------------
- */
-
-void
-TkpDeleteFont(
- TkFont *tkFontPtr) /* Token of font to be deleted. */
-{
- UnixFont *fontPtr = (UnixFont *) tkFontPtr;
-
- ReleaseFont(fontPtr);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * TkpGetFontFamilies --
- *
- * Return information about the font families that are available on the
- * display of the given window.
- *
- * Results:
- * Modifies interp's result object to hold a list of all the available
- * font families.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-void
-TkpGetFontFamilies(
- Tcl_Interp *interp, /* Interp to hold result. */
- Tk_Window tkwin) /* For display to query. */
-{
- int i, new, numNames;
- char *family, **nameList;
- Tcl_HashTable familyTable;
- Tcl_HashEntry *hPtr;
- Tcl_HashSearch search;
- Tcl_Obj *resultPtr, *strPtr;
-
- Tcl_InitHashTable(&familyTable, TCL_STRING_KEYS);
- nameList = ListFonts(Tk_Display(tkwin), "*", &numNames);
- for (i = 0; i < numNames; i++) {
- char *familyEnd;
-
- family = strchr(nameList[i] + 1, '-');
- if (family == NULL) {
- /*
- * Apparently, sometimes ListFonts() can return a font name with
- * zero or one '-' character in it. This is probably indicative of
- * a server misconfiguration, but crashing because of it is a very
- * bad idea anyway. [Bug 1475865]
- */
-
- continue;
- }
- family++; /* Advance to char after '-'. */
- familyEnd = strchr(family, '-');
- if (familyEnd == NULL) {
- continue; /* See comment above. */
- }
- *familyEnd = '\0';
- Tcl_CreateHashEntry(&familyTable, family, &new);
- }
- XFreeFontNames(nameList);
-
- hPtr = Tcl_FirstHashEntry(&familyTable, &search);
- resultPtr = Tcl_NewObj();
- while (hPtr != NULL) {
- strPtr = Tcl_NewStringObj(Tcl_GetHashKey(&familyTable, hPtr), -1);
- Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);
- hPtr = Tcl_NextHashEntry(&search);
- }
- Tcl_SetObjResult(interp, resultPtr);
-
- Tcl_DeleteHashTable(&familyTable);
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * TkpGetSubFonts --
- *
- * A function used by the testing package for querying the actual screen
- * fonts that make up a font object.
- *
- * Results:
- * Modifies interp's result object to hold a list containing the names of
- * the screen fonts that make up the given font object.
- *
- * Side effects:
- * None.
- *
- *-------------------------------------------------------------------------
- */
-
-void
-TkpGetSubFonts(
- Tcl_Interp *interp,
- Tk_Font tkfont)
-{
- int i;
- Tcl_Obj *objv[3], *resultPtr, *listPtr;
- UnixFont *fontPtr;
- FontFamily *familyPtr;
-
- resultPtr = Tcl_NewObj();
- fontPtr = (UnixFont *) tkfont;
- for (i = 0; i < fontPtr->numSubFonts; i++) {
- familyPtr = fontPtr->subFontArray[i].familyPtr;
- objv[0] = Tcl_NewStringObj(familyPtr->faceName, -1);
- objv[1] = Tcl_NewStringObj(familyPtr->foundry, -1);
- objv[2] = Tcl_NewStringObj(
- Tcl_GetEncodingName(familyPtr->encoding), -1);
- listPtr = Tcl_NewListObj(3, objv);
- Tcl_ListObjAppendElement(NULL, resultPtr, listPtr);
- }
- Tcl_SetObjResult(interp, resultPtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkpGetFontAttrsForChar --
- *
- * Retrieve the font attributes of the actual font used to render a given
- * character.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The font attributes are stored in *faPtr.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkpGetFontAttrsForChar(
- Tk_Window tkwin, /* Window on the font's display */
- Tk_Font tkfont, /* Font to query */
- Tcl_UniChar c, /* Character of interest */
- TkFontAttributes *faPtr) /* Output: Font attributes */
-{
- FontAttributes atts;
- UnixFont *fontPtr = (UnixFont *) tkfont;
- /* Structure describing the logical font */
- SubFont *lastSubFontPtr = &fontPtr->subFontArray[0];
- /* Pointer to subfont array in case
- * FindSubFontForChar needs to fix up the
- * memory allocation */
- SubFont *thisSubFontPtr = FindSubFontForChar(fontPtr, c, &lastSubFontPtr);
- /* Pointer to the subfont to use for the given
- * character */
-
- GetFontAttributes(Tk_Display(tkwin), thisSubFontPtr->fontStructPtr, &atts);
- *faPtr = atts.fa;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_MeasureChars --
- *
- * Determine the number of characters from the string that will fit in
- * the given horizontal span. The measurement is done under the
- * assumption that Tk_DrawChars() will be used to actually display the
- * characters.
- *
- * Results:
- * The return value is the number of bytes from source that fit into the
- * span that extends from 0 to maxLength. *lengthPtr is filled with the
- * x-coordinate of the right edge of the last character that did fit.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-int
-Tk_MeasureChars(
- Tk_Font tkfont, /* Font in which characters will be drawn. */
- const char *source, /* UTF-8 string to be displayed. Need not be
- * '\0' terminated. */
- int numBytes, /* Maximum number of bytes to consider from
- * source string. */
- int maxLength, /* If >= 0, maxLength specifies the longest
- * permissible line length in pixels; don't
- * consider any character that would cross
- * this x-position. If < 0, then line length
- * is unbounded and the flags argument is
- * ignored. */
- int flags, /* Various flag bits OR-ed together:
- * TK_PARTIAL_OK means include the last char
- * which only partially fit on this line.
- * TK_WHOLE_WORDS means stop on a word
- * boundary, if possible. TK_AT_LEAST_ONE
- * means return at least one character even if
- * no characters fit. */
- int *lengthPtr) /* Filled with x-location just after the
- * terminating character. */
-{
- UnixFont *fontPtr;
- SubFont *lastSubFontPtr;
- int curX, curByte;
-
- /*
- * Unix does not use kerning or fractional character widths when
- * displaying text on the screen. So that means we can safely measure
- * individual characters or spans of characters and add up the widths w/o
- * any "off-by-one-pixel" errors.
- */
-
- fontPtr = (UnixFont *) tkfont;
-
- lastSubFontPtr = &fontPtr->subFontArray[0];
-
- if (numBytes == 0) {
- curX = 0;
- curByte = 0;
- } else if (maxLength < 0) {
- const char *p, *end, *next;
- Tcl_UniChar ch;
- SubFont *thisSubFontPtr;
- FontFamily *familyPtr;
- Tcl_DString runString;
-
- /*
- * A three step process:
- * 1. Find a contiguous range of characters that can all be
- * represented by a single screen font.
- * 2. Convert those chars to the encoding of that font.
- * 3. Measure converted chars.
- */
-
- curX = 0;
- end = source + numBytes;
- for (p = source; p < end; ) {
- next = p + Tcl_UtfToUniChar(p, &ch);
- thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
- if (thisSubFontPtr != lastSubFontPtr) {
- familyPtr = lastSubFontPtr->familyPtr;
- Tcl_UtfToExternalDString(familyPtr->encoding, source,
- p - source, &runString);
- if (familyPtr->isTwoByteFont) {
- curX += XTextWidth16(lastSubFontPtr->fontStructPtr,
- (XChar2b *) Tcl_DStringValue(&runString),
- Tcl_DStringLength(&runString) / 2);
- } else {
- curX += XTextWidth(lastSubFontPtr->fontStructPtr,
- Tcl_DStringValue(&runString),
- Tcl_DStringLength(&runString));
- }
- Tcl_DStringFree(&runString);
- lastSubFontPtr = thisSubFontPtr;
- source = p;
- }
- p = next;
- }
- familyPtr = lastSubFontPtr->familyPtr;
- Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source,
- &runString);
- if (familyPtr->isTwoByteFont) {
- curX += XTextWidth16(lastSubFontPtr->fontStructPtr,
- (XChar2b *) Tcl_DStringValue(&runString),
- Tcl_DStringLength(&runString) >> 1);
- } else {
- curX += XTextWidth(lastSubFontPtr->fontStructPtr,
- Tcl_DStringValue(&runString),
- Tcl_DStringLength(&runString));
- }
- Tcl_DStringFree(&runString);
- curByte = numBytes;
- } else {
- const char *p, *end, *next, *term;
- int newX, termX, sawNonSpace, dstWrote;
- Tcl_UniChar ch;
- FontFamily *familyPtr;
- XChar2b buf[8];
-
- /*
- * How many chars will fit in the space allotted? This first version
- * may be inefficient because it measures every character
- * individually.
- */
-
- next = source + Tcl_UtfToUniChar(source, &ch);
- newX = curX = termX = 0;
-
- term = source;
- end = source + numBytes;
-
- sawNonSpace = (ch > 255) || !isspace(ch);
- familyPtr = lastSubFontPtr->familyPtr;
- for (p = source; ; ) {
- if ((ch < BASE_CHARS) && (fontPtr->widths[ch] != 0)) {
- newX += fontPtr->widths[ch];
- } else {
- lastSubFontPtr = FindSubFontForChar(fontPtr, ch, NULL);
- familyPtr = lastSubFontPtr->familyPtr;
- Tcl_UtfToExternal(NULL, familyPtr->encoding, p, next - p, 0, NULL,
- (char *)&buf[0].byte1, sizeof(buf), NULL, &dstWrote, NULL);
- if (familyPtr->isTwoByteFont) {
- newX += XTextWidth16(lastSubFontPtr->fontStructPtr,
- buf, dstWrote >> 1);
- } else {
- newX += XTextWidth(lastSubFontPtr->fontStructPtr,
- (char *)&buf[0].byte1, dstWrote);
- }
- }
- if (newX > maxLength) {
- break;
- }
- curX = newX;
- p = next;
- if (p >= end) {
- term = end;
- termX = curX;
- break;
- }
-
- next += Tcl_UtfToUniChar(next, &ch);
- if ((ch < 256) && isspace(ch)) {
- if (sawNonSpace) {
- term = p;
- termX = curX;
- sawNonSpace = 0;
- }
- } else {
- sawNonSpace = 1;
- }
- }
-
- /*
- * P points to the first character that doesn't fit in the desired
- * span. Use the flags to figure out what to return.
- */
-
- if ((flags & TK_PARTIAL_OK) && (p < end) && (curX < maxLength)) {
- /*
- * Include the first character that didn't quite fit in the
- * desired span. The width returned will include the width of that
- * extra character.
- */
-
- curX = newX;
- p += Tcl_UtfToUniChar(p, &ch);
- }
- if ((flags & TK_AT_LEAST_ONE) && (term == source) && (p < end)) {
- term = p;
- termX = curX;
- if (term == source) {
- term += Tcl_UtfToUniChar(term, &ch);
- termX = newX;
- }
- } else if ((p >= end) || !(flags & TK_WHOLE_WORDS)) {
- term = p;
- termX = curX;
- }
-
- curX = termX;
- curByte = term - source;
- }
-
- *lengthPtr = curX;
- return curByte;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * TkpMeasureCharsInContext --
- *
- * Determine the number of bytes from the string that will fit in the
- * given horizontal span. The measurement is done under the assumption
- * that TkpDrawCharsInContext() will be used to actually display the
- * characters.
- *
- * This one is almost the same as Tk_MeasureChars(), but with access to
- * all the characters on the line for context. On X11 this context isn't
- * consulted, so we just call Tk_MeasureChars().
- *
- * Results:
- * The return value is the number of bytes from source that fit into the
- * span that extends from 0 to maxLength. *lengthPtr is filled with the
- * x-coordinate of the right edge of the last character that did fit.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-int
-TkpMeasureCharsInContext(
- Tk_Font tkfont, /* Font in which characters will be drawn. */
- const char *source, /* UTF-8 string to be displayed. Need not be
- * '\0' terminated. */
- int numBytes, /* Maximum number of bytes to consider from
- * source string in all. */
- int rangeStart, /* Index of first byte to measure. */
- int rangeLength, /* Length of range to measure in bytes. */
- int maxLength, /* If >= 0, maxLength specifies the longest
- * permissible line length; don't consider any
- * character that would cross this x-position.
- * If < 0, then line length is unbounded and
- * the flags argument is ignored. */
- int flags, /* Various flag bits OR-ed together:
- * TK_PARTIAL_OK means include the last char
- * which only partially fit on this line.
- * TK_WHOLE_WORDS means stop on a word
- * boundary, if possible. TK_AT_LEAST_ONE
- * means return at least one character even if
- * no characters fit. TK_ISOLATE_END means
- * that the last character should not be
- * considered in context with the rest of the
- * string (used for breaking lines). */
- int *lengthPtr) /* Filled with x-location just after the
- * terminating character. */
-{
- (void) numBytes; /*unused*/
- return Tk_MeasureChars(tkfont, source + rangeStart, rangeLength,
- maxLength, flags, lengthPtr);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_DrawChars --
- *
- * Draw a string of characters on the screen. Tk_DrawChars() expands
- * control characters that occur in the string to \xNN sequences.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Information gets drawn on the screen.
- *
- *---------------------------------------------------------------------------
- */
-
-void
-Tk_DrawChars(
- Display *display, /* Display on which to draw. */
- Drawable drawable, /* Window or pixmap in which to draw. */
- GC gc, /* Graphics context for drawing characters. */
- Tk_Font tkfont, /* Font in which characters will be drawn;
- * must be the same as font used in GC. */
- const char *source, /* UTF-8 string to be displayed. Need not be
- * '\0' terminated. All Tk meta-characters
- * (tabs, control characters, and newlines)
- * should be stripped out of the string that
- * is passed to this function. If they are not
- * stripped out, they will be displayed as
- * regular printing characters. */
- int numBytes, /* Number of bytes in string. */
- int x, int y) /* Coordinates at which to place origin of
- * string when drawing. */
-{
- UnixFont *fontPtr = (UnixFont *) tkfont;
- SubFont *thisSubFontPtr, *lastSubFontPtr;
- Tcl_DString runString;
- const char *p, *end, *next;
- int xStart, needWidth, window_width, do_width;
- Tcl_UniChar ch;
- FontFamily *familyPtr;
-#ifdef TK_DRAW_CHAR_XWINDOW_CHECK
- int rx, ry;
- unsigned width, height, border_width, depth;
- Drawable root;
-#endif
-
- lastSubFontPtr = &fontPtr->subFontArray[0];
- xStart = x;
-
-#ifdef TK_DRAW_CHAR_XWINDOW_CHECK
- /*
- * Get the window width so we can abort drawing outside of the window
- */
-
- if (XGetGeometry(display, drawable, &root, &rx, &ry, &width, &height,
- &border_width, &depth) == False) {
- window_width = INT_MAX;
- } else {
- window_width = width;
- }
-#else
- /*
- * This is used by default until we find a solution that doesn't do a
- * round-trip to the X server (needed to get Tk cached window width).
- */
-
- window_width = 32768;
-#endif
-
- end = source + numBytes;
- needWidth = fontPtr->font.fa.underline + fontPtr->font.fa.overstrike;
- for (p = source; p <= end; ) {
- if (p < end) {
- next = p + Tcl_UtfToUniChar(p, &ch);
- thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
- } else {
- next = p + 1;
- thisSubFontPtr = lastSubFontPtr;
- }
- if ((thisSubFontPtr != lastSubFontPtr)
- || (p == end) || (p-source > 200)) {
- if (p > source) {
- do_width = (needWidth || (p != end)) ? 1 : 0;
- familyPtr = lastSubFontPtr->familyPtr;
-
- Tcl_UtfToExternalDString(familyPtr->encoding, source,
- p - source, &runString);
- if (familyPtr->isTwoByteFont) {
- XDrawString16(display, drawable, gc, x, y,
- (XChar2b *) Tcl_DStringValue(&runString),
- Tcl_DStringLength(&runString) / 2);
- if (do_width) {
- x += XTextWidth16(lastSubFontPtr->fontStructPtr,
- (XChar2b *) Tcl_DStringValue(&runString),
- Tcl_DStringLength(&runString) / 2);
- }
- } else {
- XDrawString(display, drawable, gc, x, y,
- Tcl_DStringValue(&runString),
- Tcl_DStringLength(&runString));
- if (do_width) {
- x += XTextWidth(lastSubFontPtr->fontStructPtr,
- Tcl_DStringValue(&runString),
- Tcl_DStringLength(&runString));
- }
- }
- Tcl_DStringFree(&runString);
- }
- lastSubFontPtr = thisSubFontPtr;
- source = p;
- XSetFont(display, gc, lastSubFontPtr->fontStructPtr->fid);
- if (x > window_width) {
- break;
- }
- }
- p = next;
- }
-
- if (lastSubFontPtr != &fontPtr->subFontArray[0]) {
- XSetFont(display, gc, fontPtr->subFontArray[0].fontStructPtr->fid);
- }
-
- if (fontPtr->font.fa.underline != 0) {
- XFillRectangle(display, drawable, gc, xStart,
- y + fontPtr->underlinePos,
- (unsigned) (x - xStart), (unsigned) fontPtr->barHeight);
- }
- if (fontPtr->font.fa.overstrike != 0) {
- y -= fontPtr->font.fm.descent + (fontPtr->font.fm.ascent) / 10;
- XFillRectangle(display, drawable, gc, xStart, y,
- (unsigned) (x - xStart), (unsigned) fontPtr->barHeight);
- }
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * TkpDrawCharsInContext --
- *
- * Draw a string of characters on the screen like Tk_DrawChars(), but
- * with access to all the characters on the line for context. On X11 this
- * context isn't consulted, so we just call Tk_DrawChars().
- *
- * Results:
- * None.
- *
- * Side effects:
- * Information gets drawn on the screen.
- *
- *---------------------------------------------------------------------------
- */
-
-void
-TkpDrawCharsInContext(
- Display *display, /* Display on which to draw. */
- Drawable drawable, /* Window or pixmap in which to draw. */
- GC gc, /* Graphics context for drawing characters. */
- Tk_Font tkfont, /* Font in which characters will be drawn;
- * must be the same as font used in GC. */
- const char *source, /* UTF-8 string to be displayed. Need not be
- * '\0' terminated. All Tk meta-characters
- * (tabs, control characters, and newlines)
- * should be stripped out of the string that
- * is passed to this function. If they are not
- * stripped out, they will be displayed as
- * regular printing characters. */
- int numBytes, /* Number of bytes in string. */
- int rangeStart, /* Index of first byte to draw. */
- int rangeLength, /* Length of range to draw in bytes. */
- int x, int y) /* Coordinates at which to place origin of the
- * whole (not just the range) string when
- * drawing. */
-{
- (void) numBytes; /*unused*/
-
- Tk_DrawChars(display, drawable, gc, tkfont, source + rangeStart,
- rangeLength, x, y);
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * CreateClosestFont --
- *
- * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes(). Given a
- * set of font attributes, construct a close XFontStruct. If requested
- * face name is not available, automatically substitutes an alias for
- * requested face name. If encoding is not specified (or the requested
- * one is not available), automatically chooses another encoding from the
- * list of preferred encodings. If the foundry is not specified (or is
- * not available) automatically prefers "adobe" foundry. For all other
- * attributes, if the requested value was not available, the appropriate
- * "close" value will be used.
- *
- * Results:
- * Return value is the XFontStruct that best matched the requested
- * attributes. The return value is never NULL; some font will always be
- * returned.
- *
- * Side effects:
- * None.
- *
- *-------------------------------------------------------------------------
- */
-
-static XFontStruct *
-CreateClosestFont(
- Tk_Window tkwin, /* For display where font will be used. */
- const TkFontAttributes *faPtr,
- /* Set of generic attributes to match. */
- const TkXLFDAttributes *xaPtr)
- /* Set of X-specific attributes to match. */
-{
- FontAttributes want;
- char **nameList;
- int numNames, nameIdx, bestIdx[2];
- Display *display;
- XFontStruct *fontStructPtr;
- unsigned bestScore[2];
-
- want.fa = *faPtr;
- want.xa = *xaPtr;
-
- if (want.xa.foundry == NULL) {
- want.xa.foundry = Tk_GetUid("adobe");
- }
- if (want.fa.family == NULL) {
- want.fa.family = Tk_GetUid("fixed");
- }
- want.fa.size = -TkFontGetPixels(tkwin, faPtr->size);
- if (want.xa.charset == NULL || *want.xa.charset == '\0') {
- want.xa.charset = Tk_GetUid("iso8859-1"); /* locale. */
- }
-
- display = Tk_Display(tkwin);
-
- /*
- * Algorithm to get the closest font to the name requested.
- *
- * try fontname
- * try all aliases for fontname
- * foreach fallback for fontname
- * try the fallback
- * try all aliases for the fallback
- */
-
- nameList = ListFontOrAlias(display, want.fa.family, &numNames);
- if (numNames == 0) {
- const char *const *const *fontFallbacks;
- int i, j;
- const char *fallback;
-
- fontFallbacks = TkFontGetFallbacks();
- for (i = 0; fontFallbacks[i] != NULL; i++) {
- for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {
- if (strcasecmp(want.fa.family, fallback) == 0) {
- break;
- }
- }
- if (fallback != NULL) {
- for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {
- nameList = ListFontOrAlias(display, fallback, &numNames);
- if (numNames != 0) {
- goto found;
- }
- }
- }
- }
- nameList = ListFonts(display, "fixed", &numNames);
- if (numNames == 0) {
- nameList = ListFonts(display, "*", &numNames);
- }
- if (numNames == 0) {
- return GetSystemFont(display);
- }
- }
-
- found:
- bestIdx[0] = -1;
- bestIdx[1] = -1;
- bestScore[0] = (unsigned) -1;
- bestScore[1] = (unsigned) -1;
- for (nameIdx = 0; nameIdx < numNames; nameIdx++) {
- FontAttributes got;
- int scalable;
- unsigned score;
-
- if (TkFontParseXLFD(nameList[nameIdx], &got.fa, &got.xa) != TCL_OK) {
- continue;
- }
- IdentifySymbolEncodings(&got);
- scalable = (got.fa.size == 0);
- score = RankAttributes(&want, &got);
- if (score < bestScore[scalable]) {
- bestIdx[scalable] = nameIdx;
- bestScore[scalable] = score;
- }
- if (score == 0) {
- break;
- }
- }
-
- fontStructPtr = GetScreenFont(display, &want, nameList, bestIdx,
- bestScore);
- XFreeFontNames(nameList);
-
- if (fontStructPtr == NULL) {
- return GetSystemFont(display);
- }
- return fontStructPtr;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * InitFont --
- *
- * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().
- * Initializes the memory for a new UnixFont that wraps the
- * platform-specific data.
- *
- * The caller is responsible for initializing the fields of the TkFont
- * that are used exclusively by the generic TkFont code, and for
- * releasing those fields before calling TkpDeleteFont().
- *
- * Results:
- * Fills the WinFont structure.
- *
- * Side effects:
- * Memory allocated.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-InitFont(
- Tk_Window tkwin, /* For screen where font will be used. */
- XFontStruct *fontStructPtr, /* X information about font. */
- UnixFont *fontPtr) /* Filled with information constructed from
- * the above arguments. */
-{
- ThreadSpecificData *tsdPtr =
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- unsigned long value;
- int minHi, maxHi, minLo, maxLo, fixed, width, limit, i, n;
- FontAttributes fa;
- TkFontAttributes *faPtr;
- TkFontMetrics *fmPtr;
- SubFont *controlPtr, *subFontPtr;
- char *pageMap;
- Display *display;
-
- /*
- * Get all font attributes and metrics.
- */
-
- display = Tk_Display(tkwin);
- GetFontAttributes(display, fontStructPtr, &fa);
-
- minHi = fontStructPtr->min_byte1;
- maxHi = fontStructPtr->max_byte1;
- minLo = fontStructPtr->min_char_or_byte2;
- maxLo = fontStructPtr->max_char_or_byte2;
-
- fixed = 1;
- if (fontStructPtr->per_char != NULL) {
- width = 0;
- limit = (maxHi - minHi + 1) * (maxLo - minLo + 1);
- for (i = 0; i < limit; i++) {
- n = fontStructPtr->per_char[i].width;
- if (n != 0) {
- if (width == 0) {
- width = n;
- } else if (width != n) {
- fixed = 0;
- break;
- }
- }
- }
- }
-
- fontPtr->font.fid = fontStructPtr->fid;
-
- faPtr = &fontPtr->font.fa;
- faPtr->family = fa.fa.family;
- faPtr->size = TkFontGetPoints(tkwin, fa.fa.size);
- faPtr->weight = fa.fa.weight;
- faPtr->slant = fa.fa.slant;
- faPtr->underline = 0;
- faPtr->overstrike = 0;
-
- fmPtr = &fontPtr->font.fm;
- fmPtr->ascent = fontStructPtr->ascent;
- fmPtr->descent = fontStructPtr->descent;
- fmPtr->maxWidth = fontStructPtr->max_bounds.width;
- fmPtr->fixed = fixed;
-
- fontPtr->display = display;
- fontPtr->pixelSize = TkFontGetPixels(tkwin, fa.fa.size);
- fontPtr->xa = fa.xa;
-
- fontPtr->numSubFonts = 1;
- fontPtr->subFontArray = fontPtr->staticSubFonts;
- InitSubFont(display, fontStructPtr, 1, &fontPtr->subFontArray[0]);
-
- fontPtr->controlSubFont = fontPtr->subFontArray[0];
- subFontPtr = FindSubFontForChar(fontPtr, '0', NULL);
- controlPtr = &fontPtr->controlSubFont;
- controlPtr->fontStructPtr = subFontPtr->fontStructPtr;
- controlPtr->familyPtr = &tsdPtr->controlFamily;
- controlPtr->fontMap = tsdPtr->controlFamily.fontMap;
-
- pageMap = fontPtr->subFontArray[0].fontMap[0];
- for (i = 0; i < 256; i++) {
- if ((minHi > 0) || (i < minLo) || (i > maxLo)
- || !((pageMap[i>>3] >> (i&7)) & 1)) {
- n = 0;
- } else if (fontStructPtr->per_char == NULL) {
- n = fontStructPtr->max_bounds.width;
- } else {
- n = fontStructPtr->per_char[i - minLo].width;
- }
- fontPtr->widths[i] = n;
- }
-
- if (XGetFontProperty(fontStructPtr, XA_UNDERLINE_POSITION, &value)) {
- fontPtr->underlinePos = value;
- } else {
- /*
- * If the XA_UNDERLINE_POSITION property does not exist, the X manual
- * recommends using the following value:
- */
-
- fontPtr->underlinePos = fontStructPtr->descent / 2;
- }
- fontPtr->barHeight = 0;
- if (XGetFontProperty(fontStructPtr, XA_UNDERLINE_THICKNESS, &value)) {
- fontPtr->barHeight = value;
- }
- if (fontPtr->barHeight == 0) {
- /*
- * If the XA_UNDERLINE_THICKNESS property does not exist, the X manual
- * recommends using the width of the stem on a capital letter. I don't
- * know of a way to get the stem width of a letter, so guess and use
- * 1/3 the width of a capital I.
- */
-
- fontPtr->barHeight = fontPtr->widths['I'] / 3;
- if (fontPtr->barHeight == 0) {
- fontPtr->barHeight = 1;
- }
- }
- if (fontPtr->underlinePos + fontPtr->barHeight > fontStructPtr->descent) {
- /*
- * If this set of cobbled together values would cause the bottom of
- * the underline bar to stick below the descent of the font, jack the
- * underline up a bit higher.
- */
-
- fontPtr->barHeight = fontStructPtr->descent - fontPtr->underlinePos;
- if (fontPtr->barHeight == 0) {
- fontPtr->underlinePos--;
- fontPtr->barHeight = 1;
- }
- }
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * ReleaseFont --
- *
- * Called to release the unix-specific contents of a TkFont. The caller
- * is responsible for freeing the memory used by the font itself.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Memory is freed.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-ReleaseFont(
- UnixFont *fontPtr) /* The font to delete. */
-{
- int i;
-
- for (i = 0; i < fontPtr->numSubFonts; i++) {
- ReleaseSubFont(fontPtr->display, &fontPtr->subFontArray[i]);
- }
- if (fontPtr->subFontArray != fontPtr->staticSubFonts) {
- ckfree(fontPtr->subFontArray);
- }
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * InitSubFont --
- *
- * Wrap a screen font and load the FontFamily that represents it. Used to
- * prepare a SubFont so that characters can be mapped from UTF-8 to the
- * charset of the font.
- *
- * Results:
- * The subFontPtr is filled with information about the font.
- *
- * Side effects:
- * None.
- *
- *-------------------------------------------------------------------------
- */
-
-static void
-InitSubFont(
- Display *display, /* Display in which font will be used. */
- XFontStruct *fontStructPtr, /* The screen font. */
- int base, /* Non-zero if this SubFont is being used as
- * the base font for a font object. */
- SubFont *subFontPtr) /* Filled with SubFont constructed from above
- * attributes. */
-{
- subFontPtr->fontStructPtr = fontStructPtr;
- subFontPtr->familyPtr = AllocFontFamily(display, fontStructPtr, base);
- subFontPtr->fontMap = subFontPtr->familyPtr->fontMap;
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * ReleaseSubFont --
- *
- * Called to release the contents of a SubFont. The caller is responsible
- * for freeing the memory used by the SubFont itself.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Memory and resources are freed.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-ReleaseSubFont(
- Display *display, /* Display which owns screen font. */
- SubFont *subFontPtr) /* The SubFont to delete. */
-{
- XFreeFont(display, subFontPtr->fontStructPtr);
- FreeFontFamily(subFontPtr->familyPtr);
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * AllocFontFamily --
- *
- * Find the FontFamily structure associated with the given font name.
- * The information should be stored by the caller in a SubFont and used
- * when determining if that SubFont supports a character.
- *
- * Cannot use the string name used to construct the font as the key,
- * because the capitalization may not be canonical. Therefore use the
- * face name actually retrieved from the font metrics as the key.
- *
- * Results:
- * A pointer to a FontFamily. The reference count in the FontFamily is
- * automatically incremented. When the SubFont is released, the reference
- * count is decremented. When no SubFont is using this FontFamily, it may
- * be deleted.
- *
- * Side effects:
- * A new FontFamily structure will be allocated if this font family has
- * not been seen. TrueType character existence metrics are loaded into
- * the FontFamily structure.
- *
- *-------------------------------------------------------------------------
- */
-
-static FontFamily *
-AllocFontFamily(
- Display *display, /* Display in which font will be used. */
- XFontStruct *fontStructPtr, /* Screen font whose FontFamily is to be
- * returned. */
- int base) /* Non-zero if this font family is to be used
- * in the base font of a font object. */
-{
- FontFamily *familyPtr;
- FontAttributes fa;
- Tcl_Encoding encoding;
- ThreadSpecificData *tsdPtr =
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
-
- GetFontAttributes(display, fontStructPtr, &fa);
- encoding = Tcl_GetEncoding(NULL, GetEncodingAlias(fa.xa.charset));
-
- familyPtr = tsdPtr->fontFamilyList;
- for (; familyPtr != NULL; familyPtr = familyPtr->nextPtr) {
- if ((familyPtr->faceName == fa.fa.family)
- && (familyPtr->foundry == fa.xa.foundry)
- && (familyPtr->encoding == encoding)) {
- Tcl_FreeEncoding(encoding);
- familyPtr->refCount++;
- return familyPtr;
- }
- }
-
- familyPtr = ckalloc(sizeof(FontFamily));
- memset(familyPtr, 0, sizeof(FontFamily));
- familyPtr->nextPtr = tsdPtr->fontFamilyList;
- tsdPtr->fontFamilyList = familyPtr;
-
- /*
- * Set key for this FontFamily.
- */
-
- familyPtr->foundry = fa.xa.foundry;
- familyPtr->faceName = fa.fa.family;
- familyPtr->encoding = encoding;
-
- /*
- * An initial refCount of 2 means that FontFamily information will persist
- * even when the SubFont that loaded the FontFamily is released. Change it
- * to 1 to cause FontFamilies to be unloaded when not in use.
- */
-
- familyPtr->refCount = 2;
-
- /*
- * One byte/character fonts have both min_byte1 and max_byte1 0, and
- * max_char_or_byte2 <= 255. Anything else specifies a two byte/character
- * font.
- */
-
- familyPtr->isTwoByteFont = !(
- (fontStructPtr->min_byte1 == 0) &&
- (fontStructPtr->max_byte1 == 0) &&
- (fontStructPtr->max_char_or_byte2 < 256));
- return familyPtr;
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * FreeFontFamily --
- *
- * Called to free an FontFamily when the SubFont is finished using it.
- * Frees the contents of the FontFamily and the memory used by the
- * FontFamily itself.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-------------------------------------------------------------------------
- */
-
-static void
-FreeFontFamily(
- FontFamily *familyPtr) /* The FontFamily to delete. */
-{
- FontFamily **familyPtrPtr;
- ThreadSpecificData *tsdPtr =
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- int i;
-
- if (familyPtr == NULL) {
- return;
- }
- familyPtr->refCount--;
- if (familyPtr->refCount > 0) {
- return;
- }
- Tcl_FreeEncoding(familyPtr->encoding);
- for (i = 0; i < FONTMAP_PAGES; i++) {
- if (familyPtr->fontMap[i] != NULL) {
- ckfree(familyPtr->fontMap[i]);
- }
- }
-
- /*
- * Delete from list.
- */
-
- for (familyPtrPtr = &tsdPtr->fontFamilyList; ; ) {
- if (*familyPtrPtr == familyPtr) {
- *familyPtrPtr = familyPtr->nextPtr;
- break;
- }
- familyPtrPtr = &(*familyPtrPtr)->nextPtr;
- }
-
- ckfree(familyPtr);
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * FindSubFontForChar --
- *
- * Determine which screen font is necessary to use to display the given
- * character. If the font object does not have a screen font that can
- * display the character, another screen font may be loaded into the font
- * object, following a set of preferred fallback rules.
- *
- * Results:
- * The return value is the SubFont to use to display the given character.
- *
- * Side effects:
- * The contents of fontPtr are modified to cache the results of the
- * lookup and remember any SubFonts that were dynamically loaded. The
- * table of SubFonts might be extended, and if a non-NULL reference to a
- * subfont pointer is available, it is updated if it previously pointed
- * into the old subfont table.
- *
- *-------------------------------------------------------------------------
- */
-
-static SubFont *
-FindSubFontForChar(
- UnixFont *fontPtr, /* The font object with which the character
- * will be displayed. */
- int ch, /* The Unicode character to be displayed. */
- SubFont **fixSubFontPtrPtr) /* Subfont reference to fix up if we
- * reallocate our subfont table. */
-{
- int i, j, k, numNames;
- Tk_Uid faceName;
- const char *fallback;
- const char *const *aliases;
- char **nameList;
- const char *const *anyFallbacks;
- const char *const *const *fontFallbacks;
- SubFont *subFontPtr;
- Tcl_DString ds;
-
- if (FontMapLookup(&fontPtr->subFontArray[0], ch)) {
- return &fontPtr->subFontArray[0];
- }
-
- for (i = 1; i < fontPtr->numSubFonts; i++) {
- if (FontMapLookup(&fontPtr->subFontArray[i], ch)) {
- return &fontPtr->subFontArray[i];
- }
- }
-
- if (FontMapLookup(&fontPtr->controlSubFont, ch)) {
- return &fontPtr->controlSubFont;
- }
-
- /*
- * Keep track of all face names that we check, so we don't check some name
- * multiple times if it can be reached by multiple paths.
- */
-
- Tcl_DStringInit(&ds);
-
- /*
- * Are there any other fonts with the same face name as the base font that
- * could display this character, e.g., if the base font is
- * adobe:fixed:iso8859-1, we could might be able to use
- * misc:fixed:iso8859-8 or sony:fixed:jisx0208.1983-0
- */
-
- faceName = fontPtr->font.fa.family;
- if (SeenName(faceName, &ds) == 0) {
- subFontPtr = CanUseFallback(fontPtr, faceName, ch, fixSubFontPtrPtr);
- if (subFontPtr != NULL) {
- goto end;
- }
- }
-
- aliases = TkFontGetAliasList(faceName);
-
- subFontPtr = NULL;
- fontFallbacks = TkFontGetFallbacks();
- for (i = 0; fontFallbacks[i] != NULL; i++) {
- for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {
- if (strcasecmp(fallback, faceName) == 0) {
- /*
- * If the base font has a fallback...
- */
-
- goto tryfallbacks;
- } else if (aliases != NULL) {
- /*
- * Or if an alias for the base font has a fallback...
- */
-
- for (k = 0; aliases[k] != NULL; k++) {
- if (strcasecmp(fallback, aliases[k]) == 0) {
- goto tryfallbacks;
- }
- }
- }
- }
- continue;
-
- tryfallbacks:
-
- /*
- * ...then see if we can use one of the fallbacks, or an alias for one
- * of the fallbacks.
- */
-
- for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {
- subFontPtr = CanUseFallbackWithAliases(fontPtr, fallback, ch, &ds,
- fixSubFontPtrPtr);
- if (subFontPtr != NULL) {
- goto end;
- }
- }
- }
-
- /*
- * See if we can use something from the global fallback list.
- */
-
- anyFallbacks = TkFontGetGlobalClass();
- for (i = 0; (fallback = anyFallbacks[i]) != NULL; i++) {
- subFontPtr = CanUseFallbackWithAliases(fontPtr, fallback, ch, &ds,
- fixSubFontPtrPtr);
- if (subFontPtr != NULL) {
- goto end;
- }
- }
-
- /*
- * Try all face names available in the whole system until we find one that
- * can be used.
- */
-
- nameList = ListFonts(fontPtr->display, "*", &numNames);
- for (i = 0; i < numNames; i++) {
- fallback = strchr(nameList[i] + 1, '-') + 1;
- strchr(fallback, '-')[0] = '\0';
- if (SeenName(fallback, &ds) == 0) {
- subFontPtr = CanUseFallback(fontPtr, fallback, ch,
- fixSubFontPtrPtr);
- if (subFontPtr != NULL) {
- XFreeFontNames(nameList);
- goto end;
- }
- }
- }
- XFreeFontNames(nameList);
-
- end:
- Tcl_DStringFree(&ds);
-
- if (subFontPtr == NULL) {
- /*
- * No font can display this character, so it will be displayed as a
- * control character expansion.
- */
-
- subFontPtr = &fontPtr->controlSubFont;
- FontMapInsert(subFontPtr, ch);
- }
- return subFontPtr;
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * FontMapLookup --
- *
- * See if the screen font can display the given character.
- *
- * Results:
- * The return value is 0 if the screen font cannot display the character,
- * non-zero otherwise.
- *
- * Side effects:
- * New pages are added to the font mapping cache whenever the character
- * belongs to a page that hasn't been seen before. When a page is loaded,
- * information about all the characters on that page is stored, not just
- * for the single character in question.
- *
- *-------------------------------------------------------------------------
- */
-
-static int
-FontMapLookup(
- SubFont *subFontPtr, /* Contains font mapping cache to be queried
- * and possibly updated. */
- int ch) /* Character to be tested. */
-{
- int row, bitOffset;
-
- row = ch >> FONTMAP_SHIFT;
- if (subFontPtr->fontMap[row] == NULL) {
- FontMapLoadPage(subFontPtr, row);
- }
- bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);
- return (subFontPtr->fontMap[row][bitOffset >> 3] >> (bitOffset & 7)) & 1;
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * FontMapInsert --
- *
- * Tell the font mapping cache that the given screen font should be used
- * to display the specified character. This is called when no font on the
- * system can be be found that can display that character; we lie to the
- * font and tell it that it can display the character, otherwise we would
- * end up re-searching the entire fallback hierarchy every time that
- * character was seen.
- *
- * Results:
- * None.
- *
- * Side effects:
- * New pages are added to the font mapping cache whenever the character
- * belongs to a page that hasn't been seen before. When a page is loaded,
- * information about all the characters on that page is stored, not just
- * for the single character in question.
- *
- *-------------------------------------------------------------------------
- */
-
-static void
-FontMapInsert(
- SubFont *subFontPtr, /* Contains font mapping cache to be
- * updated. */
- int ch) /* Character to be added to cache. */
-{
- int row, bitOffset;
-
- row = ch >> FONTMAP_SHIFT;
- if (subFontPtr->fontMap[row] == NULL) {
- FontMapLoadPage(subFontPtr, row);
- }
- bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);
- subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * FontMapLoadPage --
- *
- * Load information about all the characters on a given page. This
- * information consists of one bit per character that indicates whether
- * the associated screen font can (1) or cannot (0) display the
- * characters on the page.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Memory allocated.
- *
- *-------------------------------------------------------------------------
- */
-static void
-FontMapLoadPage(
- SubFont *subFontPtr, /* Contains font mapping cache to be
- * updated. */
- int row) /* Index of the page to be loaded into the
- * cache. */
-{
- char buf[16], src[TCL_UTF_MAX];
- int minHi, maxHi, minLo, maxLo, scale, checkLo;
- int i, end, bitOffset, isTwoByteFont, n;
- Tcl_Encoding encoding;
- XFontStruct *fontStructPtr;
- XCharStruct *widths;
- ThreadSpecificData *tsdPtr =
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
-
- subFontPtr->fontMap[row] = ckalloc(FONTMAP_BITSPERPAGE / 8);
- memset(subFontPtr->fontMap[row], 0, FONTMAP_BITSPERPAGE / 8);
-
- if (subFontPtr->familyPtr == &tsdPtr->controlFamily) {
- return;
- }
-
- fontStructPtr = subFontPtr->fontStructPtr;
- encoding = subFontPtr->familyPtr->encoding;
- isTwoByteFont = subFontPtr->familyPtr->isTwoByteFont;
-
- widths = fontStructPtr->per_char;
- minHi = fontStructPtr->min_byte1;
- maxHi = fontStructPtr->max_byte1;
- minLo = fontStructPtr->min_char_or_byte2;
- maxLo = fontStructPtr->max_char_or_byte2;
- scale = maxLo - minLo + 1;
- checkLo = minLo;
-
- if (! isTwoByteFont) {
- if (minLo < 32) {
- checkLo = 32;
- }
- }
-
- end = (row + 1) << FONTMAP_SHIFT;
- for (i = row << FONTMAP_SHIFT; i < end; i++) {
- int hi, lo;
-
- if (Tcl_UtfToExternal(NULL, encoding, src, Tcl_UniCharToUtf(i, src),
- TCL_ENCODING_STOPONERROR, NULL, buf, sizeof(buf), NULL,
- NULL, NULL) != TCL_OK) {
- continue;
- }
- if (isTwoByteFont) {
- hi = ((unsigned char *) buf)[0];
- lo = ((unsigned char *) buf)[1];
- } else {
- hi = 0;
- lo = ((unsigned char *) buf)[0];
- }
- if ((hi < minHi) || (hi > maxHi) || (lo < checkLo) || (lo > maxLo)) {
- continue;
- }
- n = (hi - minHi) * scale + lo - minLo;
- if ((widths == NULL) || (widths[n].width + widths[n].rbearing != 0)) {
- bitOffset = i & (FONTMAP_BITSPERPAGE - 1);
- subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);
- }
- }
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * CanUseFallbackWithAliases --
- *
- * Helper function for FindSubFontForChar. Determine if the specified
- * face name (or an alias of the specified face name) can be used to
- * construct a screen font that can display the given character.
- *
- * Results:
- * See CanUseFallback().
- *
- * Side effects:
- * If the name and/or one of its aliases was rejected, the rejected
- * string is recorded in nameTriedPtr so that it won't be tried again.
- * The table of SubFonts might be extended, and if a non-NULL reference
- * to a subfont pointer is available, it is updated if it previously
- * pointed into the old subfont table.
- *
- *---------------------------------------------------------------------------
- */
-
-static SubFont *
-CanUseFallbackWithAliases(
- UnixFont *fontPtr, /* The font object that will own the new
- * screen font. */
- const char *faceName, /* Desired face name for new screen font. */
- int ch, /* The Unicode character that the new screen
- * font must be able to display. */
- Tcl_DString *nameTriedPtr, /* Records face names that have already been
- * tried. It is possible for the same face
- * name to be queried multiple times when
- * trying to find a suitable screen font. */
- SubFont **fixSubFontPtrPtr) /* Subfont reference to fix up if we
- * reallocate our subfont table. */
-{
- SubFont *subFontPtr;
- const char *const *aliases;
- int i;
-
- if (SeenName(faceName, nameTriedPtr) == 0) {
- subFontPtr = CanUseFallback(fontPtr, faceName, ch, fixSubFontPtrPtr);
- if (subFontPtr != NULL) {
- return subFontPtr;
- }
- }
- aliases = TkFontGetAliasList(faceName);
- if (aliases != NULL) {
- for (i = 0; aliases[i] != NULL; i++) {
- if (SeenName(aliases[i], nameTriedPtr) == 0) {
- subFontPtr = CanUseFallback(fontPtr, aliases[i], ch,
- fixSubFontPtrPtr);
- if (subFontPtr != NULL) {
- return subFontPtr;
- }
- }
- }
- }
- return NULL;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * SeenName --
- *
- * Used to determine we have already tried and rejected the given face
- * name when looking for a screen font that can support some Unicode
- * character.
- *
- * Results:
- * The return value is 0 if this face name has not already been seen,
- * non-zero otherwise.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-static int
-SeenName(
- const char *name, /* The name to check. */
- Tcl_DString *dsPtr) /* Contains names that have already been
- * seen. */
-{
- const char *seen, *end;
-
- seen = Tcl_DStringValue(dsPtr);
- end = seen + Tcl_DStringLength(dsPtr);
- while (seen < end) {
- if (strcasecmp(seen, name) == 0) {
- return 1;
- }
- seen += strlen(seen) + 1;
- }
- Tcl_DStringAppend(dsPtr, name, (int) (strlen(name) + 1));
- return 0;
-}
-
-/*
- *-------------------------------------------------------------------------
- *
- * CanUseFallback --
- *
- * If the specified screen font has not already been loaded into the font
- * object, determine if the specified screen font can display the given
- * character.
- *
- * Results:
- * The return value is a pointer to a newly allocated SubFont, owned by
- * the font object. This SubFont can be used to display the given
- * character. The SubFont represents the screen font with the base set of
- * font attributes from the font object, but using the specified face
- * name. NULL is returned if the font object already holds a reference to
- * the specified font or if the specified font doesn't exist or cannot
- * display the given character.
- *
- * Side effects:
- * The font object's subFontArray is updated to contain a reference to
- * the newly allocated SubFont. The table of SubFonts might be extended,
- * and if a non-NULL reference to a subfont pointer is available, it is
- * updated if it previously pointed into the old subfont table.
- *
- *-------------------------------------------------------------------------
- */
-
-static SubFont *
-CanUseFallback(
- UnixFont *fontPtr, /* The font object that will own the new
- * screen font. */
- const char *faceName, /* Desired face name for new screen font. */
- int ch, /* The Unicode character that the new screen
- * font must be able to display. */
- SubFont **fixSubFontPtrPtr) /* Subfont reference to fix up if we
- * reallocate our subfont table. */
-{
- int i, nameIdx, numNames, srcLen, numEncodings, bestIdx[2];
- Tk_Uid hateFoundry;
- const char *charset, *hateCharset;
- unsigned bestScore[2];
- char **nameList;
- char **nameListOrig;
- char src[TCL_UTF_MAX];
- FontAttributes want, got;
- Display *display;
- SubFont subFont;
- XFontStruct *fontStructPtr;
- Tcl_DString dsEncodings;
- Tcl_Encoding *encodingCachePtr;
-
- /*
- * Assume: the face name is times.
- * Assume: adobe:times:iso8859-1 has already been used.
- *
- * Are there any versions of times that can display this character (e.g.,
- * perhaps linotype:times:iso8859-2)?
- * a. Get list of all times fonts.
- * b1. Cross out all names whose encodings we've already used.
- * b2. Cross out all names whose foundry & encoding we've already seen.
- * c. Cross out all names whose encoding cannot handle the character.
- * d. Rank each name and pick the best match.
- * e. If that font cannot actually display the character, cross out all
- * names with the same foundry and encoding and go back to (c).
- */
-
- display = fontPtr->display;
- nameList = ListFonts(display, faceName, &numNames);
- if (numNames == 0) {
- return NULL;
- }
- nameListOrig = nameList;
-
- srcLen = Tcl_UniCharToUtf(ch, src);
-
- want.fa = fontPtr->font.fa;
- want.xa = fontPtr->xa;
-
- want.fa.family = Tk_GetUid(faceName);
- want.fa.size = -fontPtr->pixelSize;
-
- hateFoundry = NULL;
- hateCharset = NULL;
- numEncodings = 0;
- Tcl_DStringInit(&dsEncodings);
-
- charset = NULL; /* lint, since numNames must be > 0 to get here. */
-
- retry:
- bestIdx[0] = -1;
- bestIdx[1] = -1;
- bestScore[0] = (unsigned) -1;
- bestScore[1] = (unsigned) -1;
- for (nameIdx = 0; nameIdx < numNames; nameIdx++) {
- Tcl_Encoding encoding;
- char dst[16];
- int scalable, srcRead, dstWrote;
- unsigned score;
-
- if (nameList[nameIdx] == NULL) {
- continue;
- }
- if (TkFontParseXLFD(nameList[nameIdx], &got.fa, &got.xa) != TCL_OK) {
- goto crossout;
- }
- IdentifySymbolEncodings(&got);
- charset = GetEncodingAlias(got.xa.charset);
- if (hateFoundry != NULL) {
- /*
- * E. If the font we picked cannot actually display the character,
- * cross out all names with the same foundry and encoding.
- */
-
- if ((hateFoundry == got.xa.foundry)
- && (strcmp(hateCharset, charset) == 0)) {
- goto crossout;
- }
- } else {
- /*
- * B. Cross out all names whose encodings we've already used.
- */
-
- for (i = 0; i < fontPtr->numSubFonts; i++) {
- encoding = fontPtr->subFontArray[i].familyPtr->encoding;
- if (strcmp(charset, Tcl_GetEncodingName(encoding)) == 0) {
- goto crossout;
- }
- }
- }
-
- /*
- * C. Cross out all names whose encoding cannot handle the character.
- */
-
- encodingCachePtr = (Tcl_Encoding *) Tcl_DStringValue(&dsEncodings);
- for (i = numEncodings; --i >= 0; encodingCachePtr++) {
- encoding = *encodingCachePtr;
- if (strcmp(Tcl_GetEncodingName(encoding), charset) == 0) {
- break;
- }
- }
- if (i < 0) {
- encoding = Tcl_GetEncoding(NULL, charset);
- if (encoding == NULL) {
- goto crossout;
- }
-
- Tcl_DStringAppend(&dsEncodings, (char *) &encoding,
- sizeof(encoding));
- numEncodings++;
- }
- Tcl_UtfToExternal(NULL, encoding, src, srcLen,
- TCL_ENCODING_STOPONERROR, NULL, dst, sizeof(dst), &srcRead,
- &dstWrote, NULL);
- if (dstWrote == 0) {
- goto crossout;
- }
-
- /*
- * D. Rank each name and pick the best match.
- */
-
- scalable = (got.fa.size == 0);
- score = RankAttributes(&want, &got);
- if (score < bestScore[scalable]) {
- bestIdx[scalable] = nameIdx;
- bestScore[scalable] = score;
- }
- if (score == 0) {
- break;
- }
- continue;
-
- crossout:
- if (nameList == nameListOrig) {
- /*
- * Not allowed to change pointers to memory that X gives you, so
- * make a copy.
- */
-
- nameList = ckalloc(numNames * sizeof(char *));
- memcpy(nameList, nameListOrig, numNames * sizeof(char *));
- }
- nameList[nameIdx] = NULL;
- }
-
- fontStructPtr = GetScreenFont(display, &want, nameList, bestIdx,
- bestScore);
-
- encodingCachePtr = (Tcl_Encoding *) Tcl_DStringValue(&dsEncodings);
- for (i = numEncodings; --i >= 0; encodingCachePtr++) {
- Tcl_FreeEncoding(*encodingCachePtr);
- }
- Tcl_DStringFree(&dsEncodings);
- numEncodings = 0;
-
- if (fontStructPtr == NULL) {
- if (nameList != nameListOrig) {
- ckfree(nameList);
- }
- XFreeFontNames(nameListOrig);
- return NULL;
- }
-
- InitSubFont(display, fontStructPtr, 0, &subFont);
- if (FontMapLookup(&subFont, ch) == 0) {
- /*
- * E. If the font we picked cannot actually display the character,
- * cross out all names with the same foundry and encoding and pick
- * another font.
- */
-
- hateFoundry = got.xa.foundry;
- hateCharset = charset;
- ReleaseSubFont(display, &subFont);
- goto retry;
- }
- if (nameList != nameListOrig) {
- ckfree(nameList);
- }
- XFreeFontNames(nameListOrig);
-
- if (fontPtr->numSubFonts >= SUBFONT_SPACE) {
- SubFont *newPtr;
-
- newPtr = ckalloc(sizeof(SubFont) * (fontPtr->numSubFonts + 1));
- memcpy(newPtr, fontPtr->subFontArray,
- fontPtr->numSubFonts * sizeof(SubFont));
- if (fixSubFontPtrPtr != NULL) {
- register SubFont *fixSubFontPtr = *fixSubFontPtrPtr;
-
- if (fixSubFontPtr != &fontPtr->controlSubFont) {
- *fixSubFontPtrPtr =
- newPtr + (fixSubFontPtr - fontPtr->subFontArray);
- }
- }
- if (fontPtr->subFontArray != fontPtr->staticSubFonts) {
- ckfree(fontPtr->subFontArray);
- }
- fontPtr->subFontArray = newPtr;
- }
- fontPtr->subFontArray[fontPtr->numSubFonts] = subFont;
- fontPtr->numSubFonts++;
- return &fontPtr->subFontArray[fontPtr->numSubFonts - 1];
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * RankAttributes --
- *
- * Determine how close the attributes of the font in question match the
- * attributes that we want.
- *
- * Results:
- * The return value is the score; lower numbers are better. *scalablePtr
- * is set to 0 if the font was not scalable, 1 otherwise.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-static unsigned
-RankAttributes(
- FontAttributes *wantPtr, /* The desired attributes. */
- FontAttributes *gotPtr) /* The attributes we have to live with. */
-{
- unsigned penalty;
-
- penalty = 0;
- if (gotPtr->xa.foundry != wantPtr->xa.foundry) {
- penalty += 4500;
- }
- if (gotPtr->fa.family != wantPtr->fa.family) {
- penalty += 9000;
- }
- if (gotPtr->fa.weight != wantPtr->fa.weight) {
- penalty += 90;
- }
- if (gotPtr->fa.slant != wantPtr->fa.slant) {
- penalty += 60;
- }
- if (gotPtr->xa.slant != wantPtr->xa.slant) {
- penalty += 10;
- }
- if (gotPtr->xa.setwidth != wantPtr->xa.setwidth) {
- penalty += 1000;
- }
-
- if (gotPtr->fa.size == 0) {
- /*
- * A scalable font is almost always acceptable, but the corresponding
- * bitmapped font would be better.
- */
-
- penalty += 10;
- } else {
- int diff;
-
- /*
- * It's worse to be too large than to be too small.
- */
-
- diff = (-gotPtr->fa.size - -wantPtr->fa.size);
- if (diff > 0) {
- penalty += 600;
- } else if (diff < 0) {
- penalty += 150;
- diff = -diff;
- }
- penalty += 150 * diff;
- }
- if (gotPtr->xa.charset != wantPtr->xa.charset) {
- int i;
- const char *gotAlias, *wantAlias;
-
- penalty += 65000;
- gotAlias = GetEncodingAlias(gotPtr->xa.charset);
- wantAlias = GetEncodingAlias(wantPtr->xa.charset);
- if (strcmp(gotAlias, wantAlias) != 0) {
- penalty += 30000;
- for (i = 0; encodingList[i] != NULL; i++) {
- if (strcmp(gotAlias, encodingList[i]) == 0) {
- penalty -= 30000;
- break;
- }
- penalty += 20000;
- }
- }
- }
- return penalty;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * GetScreenFont --
- *
- * Given the names for the best scalable and best bitmapped font,
- * actually construct an XFontStruct based on the best XLFD. This is
- * where all the alias and fallback substitution bottoms out.
- *
- * Results:
- * The screen font that best corresponds to the set of attributes.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-static XFontStruct *
-GetScreenFont(
- Display *display, /* Display for new XFontStruct. */
- FontAttributes *wantPtr, /* Contains desired actual pixel-size if the
- * best font was scalable. */
- char **nameList, /* Array of XLFDs. */
- int bestIdx[2], /* Indices into above array for XLFD of best
- * bitmapped and best scalable font. */
- unsigned bestScore[2]) /* Scores of best bitmapped and best scalable
- * font. XLFD corresponding to lowest score
- * will be constructed. */
-{
- XFontStruct *fontStructPtr;
-
- if ((bestIdx[0] < 0) && (bestIdx[1] < 0)) {
- return NULL;
- }
-
- /*
- * Now we know which is the closest matching scalable font and the closest
- * matching bitmapped font. If the scalable font was a better match, try
- * getting the scalable font; however, if the scalable font was not
- * actually available in the desired pointsize, fall back to the closest
- * bitmapped font.
- */
-
- fontStructPtr = NULL;
- if (bestScore[1] < bestScore[0]) {
- char *str, *rest, buf[256];
- int i;
-
- /*
- * Fill in the desired pixel size for this font.
- */
-
- tryscale:
- str = nameList[bestIdx[1]];
- for (i = 0; i < XLFD_PIXEL_SIZE; i++) {
- str = strchr(str + 1, '-');
- }
- rest = str;
- for (i = XLFD_PIXEL_SIZE; i < XLFD_CHARSET; i++) {
- rest = strchr(rest + 1, '-');
- }
- *str = '\0';
- sprintf(buf, "%.200s-%d-*-*-*-*-*%s", nameList[bestIdx[1]],
- -wantPtr->fa.size, rest);
- *str = '-';
- fontStructPtr = XLoadQueryFont(display, buf);
- bestScore[1] = INT_MAX;
- }
- if (fontStructPtr == NULL) {
- fontStructPtr = XLoadQueryFont(display, nameList[bestIdx[0]]);
- 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 (bestScore[1] < INT_MAX) {
- goto tryscale;
- }
- return GetSystemFont(display);
- }
- }
- return fontStructPtr;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * GetSystemFont --
- *
- * Absolute fallback mechanism, called when we need a font and no other
- * font can be found and/or instantiated.
- *
- * Results:
- * A pointer to a font. Never NULL.
- *
- * Side effects:
- * If there are NO fonts installed on the system, this call will panic,
- * but how did you get X running in that case?
- *
- *---------------------------------------------------------------------------
- */
-
-static XFontStruct *
-GetSystemFont(
- Display *display) /* Display for new XFontStruct. */
-{
- XFontStruct *fontStructPtr;
-
- fontStructPtr = XLoadQueryFont(display, "fixed");
- if (fontStructPtr == NULL) {
- fontStructPtr = XLoadQueryFont(display, "*");
- if (fontStructPtr == NULL) {
- Tcl_Panic("TkpGetFontFromAttributes: cannot get any font");
- }
- }
- return fontStructPtr;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * GetFontAttributes --
- *
- * Given a screen font, determine its actual attributes, which are not
- * necessarily the attributes that were used to construct it.
- *
- * Results:
- * *faPtr is filled with the screen font's attributes.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-static int
-GetFontAttributes(
- Display *display, /* Display that owns the screen font. */
- XFontStruct *fontStructPtr, /* Screen font to query. */
- FontAttributes *faPtr) /* For storing attributes of screen font. */
-{
- unsigned long value;
- char *name;
-
- if ((XGetFontProperty(fontStructPtr, XA_FONT, &value) != False) &&
- (value != 0)) {
- name = XGetAtomName(display, (Atom) value);
- if (TkFontParseXLFD(name, &faPtr->fa, &faPtr->xa) != TCL_OK) {
- faPtr->fa.family = Tk_GetUid(name);
- faPtr->xa.foundry = Tk_GetUid("");
- faPtr->xa.charset = Tk_GetUid("");
- }
- XFree(name);
- } else {
- TkInitFontAttributes(&faPtr->fa);
- TkInitXLFDAttributes(&faPtr->xa);
- }
-
- /*
- * Do last ditch check for family. It seems that some X servers can fail
- * on the X font calls above, slipping through earlier checks. X-Win32 5.4
- * is one of these.
- */
-
- if (faPtr->fa.family == NULL) {
- faPtr->fa.family = Tk_GetUid("");
- faPtr->xa.foundry = Tk_GetUid("");
- faPtr->xa.charset = Tk_GetUid("");
- }
- return IdentifySymbolEncodings(faPtr);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * ListFonts --
- *
- * Utility function to return the array of all XLFDs on the system with
- * the specified face name.
- *
- * Results:
- * The return value is an array of XLFDs, which should be freed with
- * XFreeFontNames(), or NULL if no XLFDs matched the requested name.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-static char **
-ListFonts(
- Display *display, /* Display to query. */
- const char *faceName, /* Desired face name, or "*" for all. */
- int *numNamesPtr) /* Filled with length of returned array, or 0
- * if no names were found. */
-{
- char buf[256];
-
- sprintf(buf, "-*-%.80s-*-*-*-*-*-*-*-*-*-*-*-*", faceName);
- return XListFonts(display, buf, 10000, numNamesPtr);
-}
-
-static char **
-ListFontOrAlias(
- Display *display, /* Display to query. */
- const char *faceName, /* Desired face name, or "*" for all. */
- int *numNamesPtr) /* Filled with length of returned array, or 0
- * if no names were found. */
-{
- char **nameList;
- const char *const *aliases;
- int i;
-
- nameList = ListFonts(display, faceName, numNamesPtr);
- if (nameList != NULL) {
- return nameList;
- }
- aliases = TkFontGetAliasList(faceName);
- if (aliases != NULL) {
- for (i = 0; aliases[i] != NULL; i++) {
- nameList = ListFonts(display, aliases[i], numNamesPtr);
- if (nameList != NULL) {
- return nameList;
- }
- }
- }
- *numNamesPtr = 0;
- return NULL;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * IdentifySymbolEncodings --
- *
- * If the font attributes refer to a symbol font, update the charset
- * field of the font attributes so that it reflects the encoding of that
- * symbol font. In general, the raw value for the charset field parsed
- * from an XLFD is meaningless for symbol fonts.
- *
- * Symbol fonts are all fonts whose name appears in the symbolClass.
- *
- * Results:
- * The return value is non-zero if the font attributes specify a symbol
- * font, or 0 otherwise. If a non-zero value is returned the charset
- * field of the font attributes will be changed to the string that
- * represents the actual encoding for the symbol font.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-static int
-IdentifySymbolEncodings(
- FontAttributes *faPtr)
-{
- int i, j;
- const char *const *aliases;
- const char *const *symbolClass;
-
- symbolClass = TkFontGetSymbolClass();
- for (i = 0; symbolClass[i] != NULL; i++) {
- if (strcasecmp(faPtr->fa.family, symbolClass[i]) == 0) {
- faPtr->xa.charset = Tk_GetUid(GetEncodingAlias(symbolClass[i]));
- return 1;
- }
- aliases = TkFontGetAliasList(symbolClass[i]);
- for (j = 0; (aliases != NULL) && (aliases[j] != NULL); j++) {
- if (strcasecmp(faPtr->fa.family, aliases[j]) == 0) {
- faPtr->xa.charset = Tk_GetUid(GetEncodingAlias(aliases[j]));
- return 1;
- }
- }
- }
- return 0;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * GetEncodingAlias --
- *
- * Map the name of an encoding to another name that should be used when
- * actually loading the encoding. For instance, the encodings
- * "jisc6226.1978", "jisx0208.1983", "jisx0208.1990", and "jisx0208.1996"
- * are well-known names for the same encoding and are represented by one
- * encoding table: "jis0208".
- *
- * Results:
- * As above. If the name has no alias, the original name is returned.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-static const char *
-GetEncodingAlias(
- const char *name) /* The name to look up. */
-{
- EncodingAlias *aliasPtr;
-
- for (aliasPtr = encodingAliases; aliasPtr->aliasPattern != NULL; ) {
- if (Tcl_StringMatch(name, aliasPtr->aliasPattern)) {
- return aliasPtr->realName;
- }
- aliasPtr++;
- }
- return name;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * TkDrawAngledChars --
- *
- * Draw some characters at an angle. This is awkward here because we have
- * no reliable way of drawing any characters at an angle in classic X11;
- * we have to draw on a Pixmap which is converted to an XImage (from
- * helper function GetImageOfText), rotate the image (hokey code!) onto
- * another XImage (from helper function InitDestImage), and then use the
- * rotated image as a mask when drawing. This is pretty awful; improved
- * versions are welcomed!
- *
- * Results:
- * None.
- *
- * Side effects:
- * Target drawable is updated.
- *
- *---------------------------------------------------------------------------
- */
-
-static inline XImage *
-GetImageOfText(
- Display *display, /* Display on which to draw. */
- Drawable drawable, /* Window or pixmap in which to draw. */
- Tk_Font tkfont, /* Font in which characters will be drawn. */
- const char *source, /* UTF-8 string to be displayed. Need not be
- * '\0' terminated. All Tk meta-characters
- * (tabs, control characters, and newlines)
- * should be stripped out of the string that
- * is passed to this function. If they are not
- * stripped out, they will be displayed as
- * regular printing characters. */
- int numBytes, /* Number of bytes in string. */
- int *realWidthPtr, int *realHeightPtr)
-{
- int width, height;
- TkFont *fontPtr = (TkFont *) tkfont;
- Pixmap bitmap;
- GC bitmapGC;
- XGCValues values;
- XImage *image;
-
- (void) Tk_MeasureChars(tkfont, source, numBytes, -1, 0, &width);
- height = fontPtr->fm.ascent + fontPtr->fm.descent;
-
- bitmap = Tk_GetPixmap(display, drawable, width, height, 1);
- values.graphics_exposures = False;
- values.foreground = BlackPixel(display, DefaultScreen(display));
- bitmapGC = XCreateGC(display, bitmap, GCGraphicsExposures|GCForeground,
- &values);
- XFillRectangle(display, bitmap, bitmapGC, 0, 0, width, height);
-
- values.font = Tk_FontId(tkfont);
- values.foreground = WhitePixel(display, DefaultScreen(display));
- values.background = BlackPixel(display, DefaultScreen(display));
- XChangeGC(display, bitmapGC, GCFont|GCForeground|GCBackground, &values);
- Tk_DrawChars(display, bitmap, bitmapGC, tkfont, source, numBytes, 0,
- fontPtr->fm.ascent);
- XFreeGC(display, bitmapGC);
-
- image = XGetImage(display, bitmap, 0, 0, width, height, AllPlanes,
- ZPixmap);
- Tk_FreePixmap(display, bitmap);
-
- *realWidthPtr = width;
- *realHeightPtr = height;
- return image;
-}
-
-static inline XImage *
-InitDestImage(
- Display *display,
- Drawable drawable,
- int width,
- int height,
- Pixmap *bitmapPtr)
-{
- Pixmap bitmap;
- XImage *image;
- GC bitmapGC;
- XGCValues values;
-
- bitmap = Tk_GetPixmap(display, drawable, width, height, 1);
- values.graphics_exposures = False;
- values.foreground = BlackPixel(display, DefaultScreen(display));
- bitmapGC = XCreateGC(display, bitmap, GCGraphicsExposures|GCForeground,
- &values);
- XFillRectangle(display, bitmap, bitmapGC, 0, 0, width, height);
- XFreeGC(display, bitmapGC);
-
- image = XGetImage(display, bitmap, 0, 0, width, height, AllPlanes,
- ZPixmap);
- *bitmapPtr = bitmap;
- return image;
-}
-
-void
-TkDrawAngledChars(
- Display *display, /* Display on which to draw. */
- Drawable drawable, /* Window or pixmap in which to draw. */
- GC gc, /* Graphics context for drawing characters. */
- Tk_Font tkfont, /* Font in which characters will be drawn;
- * must be the same as font used in GC. */
- const char *source, /* UTF-8 string to be displayed. Need not be
- * '\0' terminated. All Tk meta-characters
- * (tabs, control characters, and newlines)
- * should be stripped out of the string that
- * is passed to this function. If they are not
- * stripped out, they will be displayed as
- * regular printing characters. */
- int numBytes, /* Number of bytes in string. */
- double x, double y,
- double angle)
-{
- if (angle == 0.0) {
- Tk_DrawChars(display, drawable, gc, tkfont, source, numBytes, x, y);
- } else {
- double sinA = sin(angle * PI/180.0), cosA = cos(angle * PI/180.0);
- int bufHeight, bufWidth, srcWidth, srcHeight, i, j, dx, dy;
- Pixmap buf;
- XImage *srcImage = GetImageOfText(display, drawable, tkfont, source,
- numBytes, &srcWidth, &srcHeight);
- XImage *dstImage;
- enum {Q0=1,R1,Q1,R2,Q2,R3,Q3} quadrant;
- GC bwgc, cpgc;
- XGCValues values;
- int ascent = ((TkFont *) tkfont)->fm.ascent;
-
- /*
- * First, work out what quadrant we are operating in. We also handle
- * the rectilinear rotations as special cases. Conceptually, there's
- * also R0 (angle == 0.0) but that has been already handled as a
- * special case above.
- *
- * R1
- * Q1 | Q0
- * |
- * R2 ----+---- R0
- * |
- * Q2 | Q3
- * R3
- */
-
- if (angle < 90.0) {
- quadrant = Q0;
- } else if (angle == 90.0) {
- quadrant = R1;
- } else if (angle < 180.0) {
- quadrant = Q1;
- } else if (angle == 180.0) {
- quadrant = R2;
- } else if (angle < 270.0) {
- quadrant = Q2;
- } else if (angle == 270.0) {
- quadrant = R3;
- } else {
- quadrant = Q3;
- }
-
- if (srcImage == NULL) {
- return;
- }
- bufWidth = srcWidth*fabs(cosA) + srcHeight*fabs(sinA);
- bufHeight = srcHeight*fabs(cosA) + srcWidth*fabs(sinA);
- dstImage = InitDestImage(display, drawable, bufWidth,bufHeight, &buf);
- if (dstImage == NULL) {
- Tk_FreePixmap(display, buf);
- XDestroyImage(srcImage);
- return;
- }
-
- /*
- * Do the rotation, setting or resetting pixels in the destination
- * image dependent on whether the corresponding pixel (after rotation
- * to source image space) is set.
- */
-
- for (i=0 ; i<srcWidth ; i++) {
- for (j=0 ; j<srcHeight ; j++) {
- switch (quadrant) {
- case Q0:
- dx = ROUND16(i*cosA + j*sinA);
- dy = ROUND16(j*cosA + (srcWidth - i)*sinA);
- break;
- case R1:
- dx = j;
- dy = srcWidth - i;
- break;
- case Q1:
- dx = ROUND16((i - srcWidth)*cosA + j*sinA);
- dy = ROUND16((srcWidth-i)*sinA + (j-srcHeight)*cosA);
- break;
- case R2:
- dx = srcWidth - i;
- dy = srcHeight - j;
- break;
- case Q2:
- dx = ROUND16((i-srcWidth)*cosA + (j-srcHeight)*sinA);
- dy = ROUND16((j - srcHeight)*cosA - i*sinA);
- break;
- case R3:
- dx = srcHeight - j;
- dy = i;
- break;
- default:
- dx = ROUND16(i*cosA + (j - srcHeight)*sinA);
- dy = ROUND16(j*cosA - i*sinA);
- }
-
- if (dx < 0 || dy < 0 || dx >= bufWidth || dy >= bufHeight) {
- continue;
- }
- XPutPixel(dstImage, dx, dy,
- XGetPixel(dstImage,dx,dy) | XGetPixel(srcImage,i,j));
- }
- }
- XDestroyImage(srcImage);
-
- /*
- * Schlep the data back to the Xserver.
- */
-
- values.function = GXcopy;
- values.foreground = WhitePixel(display, DefaultScreen(display));
- values.background = BlackPixel(display, DefaultScreen(display));
- bwgc = XCreateGC(display, buf, GCFunction|GCForeground|GCBackground,
- &values);
- XPutImage(display, buf, bwgc, dstImage, 0,0, 0,0, bufWidth,bufHeight);
- XFreeGC(display, bwgc);
- XDestroyImage(dstImage);
-
- /*
- * Calculate where we want to draw the text.
- */
-
- switch (quadrant) {
- case Q0:
- dx = x;
- dy = y - srcWidth*sinA;
- break;
- case R1:
- dx = x;
- dy = y - srcWidth;
- break;
- case Q1:
- dx = x + srcWidth*cosA;
- dy = y + srcHeight*cosA - srcWidth*sinA;
- break;
- case R2:
- dx = x - srcWidth;
- dy = y - srcHeight;
- break;
- case Q2:
- dx = x + srcWidth*cosA + srcHeight*sinA;
- dy = y + srcHeight*cosA;
- break;
- case R3:
- dx = x - srcHeight;
- dy = y;
- break;
- default:
- dx = x + srcHeight*sinA;
- dy = y;
- }
-
- /*
- * Apply a correction to deal with the fact that we aren't told to
- * draw from our top-left corner but rather from the left-end of our
- * baseline.
- */
-
- dx -= ascent*sinA;
- dy -= ascent*cosA;
-
- /*
- * Transfer the text to the screen. This is done by using it as a mask
- * and then drawing through that mask with the original drawing color.
- */
-
- values.function = GXcopy;
- values.fill_style = FillSolid;
- values.clip_mask = buf;
- values.clip_x_origin = dx;
- values.clip_y_origin = dy;
- cpgc = XCreateGC(display, drawable,
- GCFunction|GCFillStyle|GCClipMask|GCClipXOrigin|GCClipYOrigin,
- &values);
- XCopyGC(display, gc, GCForeground, cpgc);
- XFillRectangle(display, drawable, cpgc, dx, dy, bufWidth,
- bufHeight);
- XFreeGC(display, cpgc);
-
- Tk_FreePixmap(display, buf);
- return;
- }
-}
-
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * End:
- */