summaryrefslogtreecommitdiffstats
path: root/mac/tkMacFont.c
diff options
context:
space:
mode:
authorstanton <stanton>1999-04-16 01:51:06 (GMT)
committerstanton <stanton>1999-04-16 01:51:06 (GMT)
commit03656f44f81469f459031fa3a4a7b09c8bc77712 (patch)
tree31378e81bd58f8c726fc552d6b30cbf3ca07497b /mac/tkMacFont.c
parent404fc236f34304df53b7e44bc7971d786b87d453 (diff)
downloadtk-03656f44f81469f459031fa3a4a7b09c8bc77712.zip
tk-03656f44f81469f459031fa3a4a7b09c8bc77712.tar.gz
tk-03656f44f81469f459031fa3a4a7b09c8bc77712.tar.bz2
* Merged 8.1 branch into the main trunk
Diffstat (limited to 'mac/tkMacFont.c')
-rw-r--r--mac/tkMacFont.c1988
1 files changed, 1714 insertions, 274 deletions
diff --git a/mac/tkMacFont.c b/mac/tkMacFont.c
index 1a75249..b68f414 100644
--- a/mac/tkMacFont.c
+++ b/mac/tkMacFont.c
@@ -10,36 +10,389 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkMacFont.c,v 1.3 1999/04/16 01:25:54 stanton Exp $
+ * RCS: @(#) $Id: tkMacFont.c,v 1.4 1999/04/16 01:51:30 stanton Exp $
*/
#include <Windows.h>
#include <Strings.h>
#include <Fonts.h>
+#include <Script.h>
#include <Resources.h>
+#include <TextUtils.h>
#include "tkMacInt.h"
#include "tkFont.h"
-#include "tkPort.h"
/*
- * The following structure represents the Macintosh's' implementation of a
- * font.
+ * For doing things with Mac strings and Fixed numbers. This probably should move
+ * the mac header file.
*/
+#ifndef StrLength
+#define StrLength(s) (*((unsigned char *) (s)))
+#endif
+#ifndef StrBody
+#define StrBody(s) ((char *) (s) + 1)
+#endif
+#define pstrcmp(s1, s2) RelString((s1), (s2), 1, 1)
+#define pstrcasecmp(s1, s2) RelString((s1), (s2), 0, 1)
+
+#ifndef Fixed2Int
+#define Fixed2Int(f) ((f) >> 16)
+#define Int2Fixed(i) ((i) << 16)
+#endif
+
+/*
+ * The preferred font encodings.
+ */
+
+static CONST char *encodingList[] = {
+ "macRoman", "macJapan", NULL
+};
+
+/*
+ * The following structures are used to map the script/language codes of a
+ * font to the name that should be passed to Tcl_GetTextEncoding() to obtain
+ * the encoding for that font. The set of numeric constants is fixed and
+ * defined by Apple.
+ */
+
+static TkStateMap scriptMap[] = {
+ {smRoman, "macRoman"},
+ {smJapanese, "macJapan"},
+ {smTradChinese, "macChinese"},
+ {smKorean, "macKorean"},
+ {smArabic, "macArabic"},
+ {smHebrew, "macHebrew"},
+ {smGreek, "macGreek"},
+ {smCyrillic, "macCyrillic"},
+ {smRSymbol, "macRSymbol"},
+ {smDevanagari, "macDevanagari"},
+ {smGurmukhi, "macGurmukhi"},
+ {smGujarati, "macGujarati"},
+ {smOriya, "macOriya"},
+ {smBengali, "macBengali"},
+ {smTamil, "macTamil"},
+ {smTelugu, "macTelugu"},
+ {smKannada, "macKannada"},
+ {smMalayalam, "macMalayalam"},
+ {smSinhalese, "macSinhalese"},
+ {smBurmese, "macBurmese"},
+ {smKhmer, "macKhmer"},
+ {smThai, "macThailand"},
+ {smLaotian, "macLaos"},
+ {smGeorgian, "macGeorgia"},
+ {smArmenian, "macArmenia"},
+ {smSimpChinese, "macSimpChinese"},
+ {smTibetan, "macTIbet"},
+ {smMongolian, "macMongolia"},
+ {smGeez, "macEthiopia"},
+ {smEastEurRoman, "macCentEuro"},
+ {smVietnamese, "macVietnam"},
+ {smExtArabic, "macSindhi"},
+ {NULL, NULL}
+};
+
+static TkStateMap romanMap[] = {
+ {langCroatian, "macCroatian"},
+ {langSlovenian, "macCroatian"},
+ {langIcelandic, "macIceland"},
+ {langRomanian, "macRomania"},
+ {langTurkish, "macTurkish"},
+ {langGreek, "macGreek"},
+ {NULL, NULL}
+};
+
+static TkStateMap cyrillicMap[] = {
+ {langUkrainian, "macUkraine"},
+ {langBulgarian, "macBulgaria"},
+ {NULL, 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 Macintosh, a "font family" is uniquely identified by its face number.
+ */
+
+
+#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.
+ */
+
+ short faceNum; /* Unique face number key for this FontFamily. */
+
+ /*
+ * Derived properties.
+ */
+
+ Tcl_Encoding encoding; /* Encoding for this font family. */
+ int isSymbolFont; /* Non-zero if this is a symbol family. */
+ int isMultiByteFont; /* Non-zero if this is a multi-byte family. */
+ char typeTable[256]; /* Table that identfies all lead bytes for a
+ * multi-byte family, used when measuring chars.
+ * If a byte is a lead byte, the value at the
+ * corresponding position in the typeTable is 1,
+ * otherwise 0. If this is a single-byte font,
+ * all entries are 0. */
+ 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 added. 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. */
+ FontFamily *familyPtr; /* The FontFamily for this SubFont. */
+} SubFont;
+
+/*
+ * The following structure represents Macintosh's implementation of a font
+ * object.
+ */
+
+#define SUBFONT_SPACE 3
+
typedef struct MacFont {
TkFont font; /* Stuff used by generic font package. Must
* be first in structure. */
- short family;
- short size;
- short style;
+ 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. */
+
+ short size; /* Font size in pixels, constructed from
+ * font attributes. */
+ short style; /* Style bits, constructed from font
+ * attributes. */
} MacFont;
+/*
+ * The following structure is used to map between the UTF-8 name for a font and
+ * the name that the Macintosh uses to refer to the font, in order to determine
+ * if a font exists. The Macintosh names for fonts are stored in the encoding
+ * of the font itself.
+ */
+
+typedef struct FontNameMap {
+ Tk_Uid utfName; /* The name of the font in UTF-8. */
+ StringPtr nativeName; /* The name of the font in the font's encoding. */
+ short faceNum; /* Unique face number for this font. */
+} FontNameMap;
+
+/*
+ * 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.
+ */
+
+static FontFamily *fontFamilyList = NULL;
+
+/*
+ * Information cached about the system at startup time.
+ */
+
+static FontNameMap *gFontNameMap = NULL;
static GWorldPtr gWorld = NULL;
-static TkFont * AllocMacFont _ANSI_ARGS_((TkFont *tkfont,
- Tk_Window tkwin, int family, int size, int style));
+/*
+ * Procedures used only in this file.
+ */
+
+static FontFamily * AllocFontFamily(CONST MacFont *fontPtr, int family);
+static SubFont * CanUseFallback(MacFont *fontPtr,
+ CONST char *fallbackName, int ch);
+static SubFont * CanUseFallbackWithAliases(MacFont *fontPtr,
+ char *faceName, int ch, Tcl_DString *nameTriedPtr);
+static SubFont * FindSubFontForChar(MacFont *fontPtr, int ch);
+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 *familyPtr);
+static void InitFont(Tk_Window tkwin, int family, int size,
+ int style, MacFont *fontPtr);
+static void InitSubFont(CONST MacFont *fontPtr, int family,
+ SubFont *subFontPtr);
+static void MultiFontDrawText(MacFont *fontPtr,
+ CONST char *source, int numBytes, int x, int y);
+static void ReleaseFont(MacFont *fontPtr);
+static void ReleaseSubFont(SubFont *subFontPtr);
+static int SeenName(CONST char *name, Tcl_DString *dsPtr);
+
+static char * BreakLine(FontFamily *familyPtr, int flags,
+ CONST char *source, int numBytes, int *widthPtr);
+static int GetFamilyNum(CONST char *faceName, short *familyPtr);
+static int GetFamilyOrAliasNum(CONST char *faceName,
+ short *familyPtr);
+static Tcl_Encoding GetFontEncoding(int faceNum, int allowSymbol,
+ int *isSymbolPtr);
+static Tk_Uid GetUtfFaceName(StringPtr faceNameStr);
+
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * TkpFontPkgInit --
+ *
+ * This procedure is called when an application is created. It
+ * initializes all the structures that are used by the
+ * platform-dependant code on a per application basis.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * See comments below.
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+TkpFontPkgInit(mainPtr)
+ TkMainInfo *mainPtr; /* The application being created. */
+{
+ MenuHandle fontMenu;
+ FontNameMap *tmpFontNameMap, *newFontNameMap, *mapPtr;
+ int i, j, numFonts, fontMapOffset, isSymbol;
+ Str255 nativeName;
+ Tcl_DString ds;
+ Tcl_Encoding encoding;
+ Tcl_Encoding *encodings;
+
+ if (gWorld == NULL) {
+ /*
+ * Do the following one time only.
+ */
+
+ Rect rect = {0, 0, 1, 1};
+
+ SetFractEnable(0);
+
+ /*
+ * Used for saving and restoring state while drawing and measuring.
+ */
+
+ if (NewGWorld(&gWorld, 0, &rect, NULL, NULL, 0) != noErr) {
+ panic("TkpFontPkgInit: NewGWorld failed");
+ }
+
+ /*
+ * The name of each font is stored in the encoding of that font.
+ * How would we translate a name from UTF-8 into the native encoding
+ * of the font unless we knew the encoding of that font? We can't.
+ * So, precompute the UTF-8 and native names of all fonts on the
+ * system. The when the user asks for font by its UTF-8 name, we
+ * lookup the name in that table and really ask for the font by its
+ * native name. Any unknown UTF-8 names will be mapped to the system
+ * font.
+ */
+
+ fontMenu = NewMenu('FT', "\px");
+ AddResMenu(fontMenu, 'FONT');
+
+ numFonts = CountMItems(fontMenu);
+ tmpFontNameMap = (FontNameMap *) ckalloc(sizeof(FontNameMap) * numFonts);
+ encodings = (Tcl_Encoding *) ckalloc(sizeof(Tcl_Encoding) * numFonts);
+
+ mapPtr = tmpFontNameMap;
+ for (i = 0; i < numFonts; i++) {
+ GetMenuItemText(fontMenu, i + 1, nativeName);
+ GetFNum(nativeName, &mapPtr->faceNum);
+ encodings[i] = GetFontEncoding(mapPtr->faceNum, 0, &isSymbol);
+ Tcl_ExternalToUtfDString(encodings[i], StrBody(nativeName),
+ StrLength(nativeName), &ds);
+ mapPtr->utfName = Tk_GetUid(Tcl_DStringValue(&ds));
+ mapPtr->nativeName = (StringPtr) ckalloc(StrLength(nativeName) + 1);
+ memcpy(mapPtr->nativeName, nativeName, StrLength(nativeName) + 1);
+ Tcl_DStringFree(&ds);
+ mapPtr++;
+ }
+ DisposeMenu(fontMenu);
+
+ /*
+ * Reorder FontNameMap so fonts with the preferred encodings are at
+ * the front of the list. The relative order of fonts that all have
+ * the same encoding is preserved. Fonts with unknown encodings get
+ * stuck at the end.
+ */
+
+ newFontNameMap = (FontNameMap *) ckalloc(sizeof(FontNameMap) * (numFonts + 1));
+ fontMapOffset = 0;
+ for (i = 0; encodingList[i] != NULL; i++) {
+ encoding = Tcl_GetEncoding(NULL, encodingList[i]);
+ if (encoding == NULL) {
+ continue;
+ }
+ for (j = 0; j < numFonts; j++) {
+ if (encodings[j] == encoding) {
+ newFontNameMap[fontMapOffset] = tmpFontNameMap[j];
+ fontMapOffset++;
+ Tcl_FreeEncoding(encodings[j]);
+ tmpFontNameMap[j].utfName = NULL;
+ }
+ }
+ Tcl_FreeEncoding(encoding);
+ }
+ for (i = 0; i < numFonts; i++) {
+ if (tmpFontNameMap[i].utfName != NULL) {
+ newFontNameMap[fontMapOffset] = tmpFontNameMap[i];
+ fontMapOffset++;
+ Tcl_FreeEncoding(encodings[i]);
+ }
+ }
+ if (fontMapOffset != numFonts) {
+ panic("TkpFontPkgInit: unexpected number of fonts");
+ }
+
+ mapPtr = &newFontNameMap[numFonts];
+ mapPtr->utfName = NULL;
+ mapPtr->nativeName = NULL;
+ mapPtr->faceNum = 0;
+
+ ckfree((char *) tmpFontNameMap);
+ ckfree((char *) encodings);
+
+ gFontNameMap = newFontNameMap;
+ }
+}
/*
*---------------------------------------------------------------------------
@@ -73,6 +426,7 @@ TkpGetNativeFont(
CONST char *name) /* Platform-specific font name. */
{
short family;
+ MacFont *fontPtr;
if (strcmp(name, "system") == 0) {
family = GetSysFont();
@@ -81,8 +435,11 @@ TkpGetNativeFont(
} else {
return NULL;
}
-
- return AllocMacFont(NULL, tkwin, family, 0, 0);
+
+ fontPtr = (MacFont *) ckalloc(sizeof(MacFont));
+ InitFont(tkwin, family, 0, 0, fontPtr);
+
+ return (TkFont *) fontPtr;
}
/*
@@ -122,41 +479,47 @@ TkpGetFontFromAttributes(
* 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. */
+ CONST TkFontAttributes *faPtr)
+ /* Set of attributes to match. */
{
- char buf[257];
- size_t len;
- short family, size, style;
-
- if (faPtr->family == NULL) {
- family = 0;
- } else {
- CONST char *familyName;
-
- familyName = faPtr->family;
- if (strcasecmp(familyName, "Times New Roman") == 0) {
- familyName = "Times";
- } else if (strcasecmp(familyName, "Courier New") == 0) {
- familyName = "Courier";
- } else if (strcasecmp(familyName, "Arial") == 0) {
- familyName = "Helvetica";
- }
-
- len = strlen(familyName);
- if (len > 255) {
- len = 255;
+ short faceNum, style;
+ int i, j;
+ char *faceName, *fallback;
+ char ***fallbacks;
+ MacFont *fontPtr;
+
+ /*
+ * Algorithm to get the closest font to the one requested.
+ *
+ * try fontname
+ * try all aliases for fontname
+ * foreach fallback for fontname
+ * try the fallback
+ * try all aliases for the fallback
+ */
+
+ faceNum = 0;
+ faceName = faPtr->family;
+ if (faceName != NULL) {
+ if (GetFamilyOrAliasNum(faceName, &faceNum) != 0) {
+ goto found;
+ }
+ fallbacks = TkFontGetFallbacks();
+ for (i = 0; fallbacks[i] != NULL; i++) {
+ for (j = 0; (fallback = fallbacks[i][j]) != NULL; j++) {
+ if (strcasecmp(faceName, fallback) == 0) {
+ for (j = 0; (fallback = fallbacks[i][j]) != NULL; j++) {
+ if (GetFamilyOrAliasNum(fallback, &faceNum)) {
+ goto found;
+ }
+ }
+ }
+ break;
+ }
}
- buf[0] = (char) len;
- memcpy(buf + 1, familyName, len);
- buf[len + 1] = '\0';
- GetFNum((StringPtr) buf, &family);
}
-
- size = faPtr->pointsize;
- if (size <= 0) {
- size = GetDefFontSize();
- }
-
+
+ found:
style = 0;
if (faPtr->weight != TK_FW_NORMAL) {
style |= bold;
@@ -167,8 +530,15 @@ TkpGetFontFromAttributes(
if (faPtr->underline) {
style |= underline;
}
-
- return AllocMacFont(tkFontPtr, tkwin, family, size, style);
+ if (tkFontPtr == NULL) {
+ fontPtr = (MacFont *) ckalloc(sizeof(MacFont));
+ } else {
+ fontPtr = (MacFont *) tkFontPtr;
+ ReleaseFont(fontPtr);
+ }
+ InitFont(tkwin, faceNum, faPtr->size, style, fontPtr);
+
+ return (TkFont *) fontPtr;
}
/*
@@ -194,7 +564,10 @@ void
TkpDeleteFont(
TkFont *tkFontPtr) /* Token of font to be deleted. */
{
- ckfree((char *) tkFontPtr);
+ MacFont *fontPtr;
+
+ fontPtr = (MacFont *) tkFontPtr;
+ ReleaseFont(fontPtr);
}
/*
@@ -206,7 +579,7 @@ TkpDeleteFont(
* on the display of the given window.
*
* Results:
- * interp->result is modified to hold a list of all the available
+ * Modifies interp's result object to hold a list of all the available
* font families.
*
* Side effects:
@@ -220,76 +593,54 @@ TkpGetFontFamilies(
Tcl_Interp *interp, /* Interp to hold result. */
Tk_Window tkwin) /* For display to query. */
{
- MenuHandle fontMenu;
- int i;
- char itemText[257];
-
- fontMenu = NewMenu(1, "\px");
- AddResMenu(fontMenu, 'FONT');
-
- for (i = 1; i < CountMItems(fontMenu); i++) {
- /*
- * Each item is a pascal string. Convert it to C and append.
- */
- GetMenuItemText(fontMenu, i, (unsigned char *) itemText);
- itemText[itemText[0] + 1] = '\0';
- Tcl_AppendElement(interp, &itemText[1]);
+ FontNameMap *mapPtr;
+ Tcl_Obj *resultPtr, *strPtr;
+
+ resultPtr = Tcl_GetObjResult(interp);
+ for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) {
+ strPtr = Tcl_NewStringObj(mapPtr->utfName, -1);
+ Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);
}
- DisposeMenu(fontMenu);
}
-
/*
- *---------------------------------------------------------------------------
+ *-------------------------------------------------------------------------
*
- * TkMacIsCharacterMissing --
+ * TkpGetSubFonts --
*
- * Given a tkFont and a character determines whether the character has
- * a glyph defined in the font or not. Note that this is potentially
- * not compatible with Mac OS 8 as it looks at the font handle
- * structure directly. Looks into the character array of the font
- * handle to determine whether the glyph is defined or not.
+ * A function used by the testing package for querying the actual
+ * screen fonts that make up a font object.
*
* Results:
- * Returns a 1 if the character is missing, a 0 if it is not.
+ * 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.
*
- *---------------------------------------------------------------------------
+ *-------------------------------------------------------------------------
*/
-
-int
-TkMacIsCharacterMissing(
- Tk_Font tkfont, /* The font we are looking in. */
- unsigned int searchChar) /* The character we are looking for. */
+
+void
+TkpGetSubFonts(interp, tkfont)
+ Tcl_Interp *interp; /* Interp to hold result. */
+ Tk_Font tkfont; /* Font object to query. */
{
- MacFont *fontPtr = (MacFont *) tkfont;
- FMInput fm;
- FontRec **fontRecHandle;
-
- fm.family = fontPtr->family;
- fm.size = fontPtr->size;
- fm.face = fontPtr->style;
- fm.needBits = 0;
- fm.device = 0;
- fm.numer.h = fm.numer.v = fm.denom.h = fm.denom.v = 1;
+ int i;
+ Tcl_Obj *resultPtr, *strPtr;
+ MacFont *fontPtr;
+ FontFamily *familyPtr;
+ Str255 nativeName;
- /*
- * This element of the FMOutput structure was changed between the 2.0 & 3.0
- * versions of the Universal Headers.
- */
-
-#if !defined(UNIVERSAL_INTERFACES_VERSION) || (UNIVERSAL_INTERFACES_VERSION < 0x0300)
- fontRecHandle = (FontRec **) FMSwapFont(&fm)->fontResult;
-#else
- fontRecHandle = (FontRec **) FMSwapFont(&fm)->fontHandle;
-#endif
- return *(short *) ((long) &(*fontRecHandle)->owTLoc
- + ((long)((*fontRecHandle)->owTLoc + searchChar
- - (*fontRecHandle)->firstChar) * sizeof(short))) == -1;
+ resultPtr = Tcl_GetObjResult(interp);
+ fontPtr = (MacFont *) tkfont;
+ for (i = 0; i < fontPtr->numSubFonts; i++) {
+ familyPtr = fontPtr->subFontArray[i].familyPtr;
+ GetFontName(familyPtr->faceNum, nativeName);
+ strPtr = Tcl_NewStringObj(GetUtfFaceName(nativeName), -1);
+ Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);
+ }
}
-
/*
*---------------------------------------------------------------------------
@@ -302,7 +653,7 @@ TkMacIsCharacterMissing(
* the characters.
*
* Results:
- * The return value is the number of characters from source that
+ * 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.
@@ -316,14 +667,14 @@ TkMacIsCharacterMissing(
int
Tk_MeasureChars(
Tk_Font tkfont, /* Font in which characters will be drawn. */
- CONST char *source, /* Characters to be displayed. Need not be
+ CONST char *source, /* UTF-8 string to be displayed. Need not be
* '\0' terminated. */
- int numChars, /* Maximum number of characters to consider
+ int numBytes, /* Maximum number of bytes to consider
* from source string. */
- int maxLength, /* If > 0, maxLength specifies the longest
+ 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
+ * x-position. If < 0, then line length is
* unbounded and the flags argument is
* ignored. */
int flags, /* Various flag bits OR-ed together:
@@ -336,134 +687,270 @@ Tk_MeasureChars(
int *lengthPtr) /* Filled with x-location just after the
* terminating character. */
{
- short staticWidths[128];
- short *widths;
- CONST char *p, *term;
- int curX, termX, curIdx, sawNonSpace;
MacFont *fontPtr;
+ FontFamily *lastFamilyPtr;
CGrafPtr saveWorld;
GDHandle saveDevice;
+ int curX, curByte;
- if (numChars == 0) {
- *lengthPtr = 0;
- return 0;
- }
-
- if (gWorld == NULL) {
- Rect rect = {0, 0, 1, 1};
+ /*
+ * According to "Inside Macintosh: Text", the Macintosh may
+ * automatically substitute
+ * ligatures or context-sensitive presentation forms when
+ * measuring/displaying text within a font run. We cannot safely
+ * measure individual characters and add up the widths w/o errors.
+ * However, if we convert a range of text from UTF-8 to, say,
+ * Shift-JIS, and get the offset into the Shift-JIS string as to
+ * where a word or line break would occur, then can we map that
+ * number back to UTF-8?
+ */
+
+ fontPtr = (MacFont *) tkfont;
- if (NewGWorld(&gWorld, 0, &rect, NULL, NULL, 0) != noErr) {
- panic("NewGWorld failed in Tk_MeasureChars");
- }
- }
GetGWorld(&saveWorld, &saveDevice);
SetGWorld(gWorld, NULL);
-
- fontPtr = (MacFont *) tkfont;
- TextFont(fontPtr->family);
+
TextSize(fontPtr->size);
TextFace(fontPtr->style);
- if (maxLength <= 0) {
- *lengthPtr = TextWidth(source, 0, numChars);
- SetGWorld(saveWorld, saveDevice);
- return numChars;
- }
-
- if (numChars > maxLength) {
- /*
- * Assume that all chars are at least 1 pixel wide, so there's no
- * need to measure more characters than there are pixels. This
- * assumption could be refined to an iterative approach that would
- * use that as a starting point and try more chars if necessary (if
- * there actually were some zero-width chars).
- */
-
- numChars = maxLength;
- }
- if (numChars > SHRT_MAX) {
- /*
- * If they are trying to measure more than 32767 chars at one time,
- * it would require several separate measurements.
- */
-
- numChars = SHRT_MAX;
- }
-
- widths = staticWidths;
- if (numChars >= sizeof(staticWidths) / sizeof(staticWidths[0])) {
- widths = (short *) ckalloc((numChars + 1) * sizeof(short));
- }
+ lastFamilyPtr = fontPtr->subFontArray[0].familyPtr;
- MeasureText((short) numChars, source, widths);
-
- if (widths[numChars] <= maxLength) {
- curX = widths[numChars];
- curIdx = numChars;
+ if (numBytes == 0) {
+ curX = 0;
+ curByte = 0;
+ } else if (maxLength < 0) {
+ CONST char *p, *end, *next;
+ Tcl_UniChar ch;
+ FontFamily *thisFamilyPtr;
+ 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);
+ thisFamilyPtr = FindSubFontForChar(fontPtr, ch)->familyPtr;
+ if (thisFamilyPtr != lastFamilyPtr) {
+ TextFont(lastFamilyPtr->faceNum);
+ Tcl_UtfToExternalDString(lastFamilyPtr->encoding, source,
+ p - source, &runString);
+ curX += TextWidth(Tcl_DStringValue(&runString), 0,
+ Tcl_DStringLength(&runString));
+ Tcl_DStringFree(&runString);
+ lastFamilyPtr = thisFamilyPtr;
+ source = p;
+ }
+ p = next;
+ }
+ TextFont(lastFamilyPtr->faceNum);
+ Tcl_UtfToExternalDString(lastFamilyPtr->encoding, source, p - source,
+ &runString);
+ curX += TextWidth(Tcl_DStringValue(&runString), 0,
+ Tcl_DStringLength(&runString));
+ Tcl_DStringFree(&runString);
+ curByte = numBytes;
} else {
- p = term = source;
- curX = termX = 0;
-
- sawNonSpace = !isspace(UCHAR(*p));
- for (curIdx = 1; ; curIdx++) {
- if (isspace(UCHAR(*p))) {
- if (sawNonSpace) {
- term = p;
- termX = widths[curIdx - 1];
- sawNonSpace = 0;
- }
- } else {
- sawNonSpace = 1;
- }
- if (widths[curIdx] > maxLength) {
- curIdx--;
- curX = widths[curIdx];
- break;
+ CONST char *p, *end, *next, *sourceOrig;
+ int widthLeft;
+ FontFamily *thisFamilyPtr;
+ Tcl_UniChar ch;
+ char *rest;
+
+ /*
+ * How many chars will fit in the space allotted?
+ */
+
+ if (maxLength > 32767) {
+ maxLength = 32767;
+ }
+
+ widthLeft = maxLength;
+ sourceOrig = source;
+ end = source + numBytes;
+ for (p = source; p < end; p = next) {
+ next = p + Tcl_UtfToUniChar(p, &ch);
+ thisFamilyPtr = FindSubFontForChar(fontPtr, ch)->familyPtr;
+ if (thisFamilyPtr != lastFamilyPtr) {
+ if (p > source) {
+ rest = BreakLine(lastFamilyPtr, flags, source,
+ p - source, &widthLeft);
+ flags &= ~TK_AT_LEAST_ONE;
+ if (rest != NULL) {
+ p = source;
+ break;
+ }
+ }
+ lastFamilyPtr = thisFamilyPtr;
+ source = p;
}
- p++;
}
- if (flags & TK_PARTIAL_OK) {
- curIdx++;
- curX = widths[curIdx];
+
+ if (p > source) {
+ rest = BreakLine(lastFamilyPtr, flags, source, p - source,
+ &widthLeft);
}
- if ((curIdx == 0) && (flags & TK_AT_LEAST_ONE)) {
- /*
- * The space was too small to hold even one character. Since at
- * least one character must always fit on a line, return the width
- * of the first character.
- */
-
- curX = TextWidth(source, 0, 1);
- curIdx = 1;
- } else if (flags & TK_WHOLE_WORDS) {
- /*
- * Break at last word that fits on the line.
- */
-
- if ((flags & TK_AT_LEAST_ONE) && (term == source)) {
- /*
- * The space was too small to hold an entire word. This
- * is the only word on the line, so just return the part of th
- * word that fit.
- */
-
- ;
- } else {
- curIdx = term - source;
- curX = termX;
- }
- }
+
+ if (rest == NULL) {
+ curByte = numBytes;
+ } else {
+ curByte = rest - sourceOrig;
+ }
+ curX = maxLength - widthLeft;
}
- if (widths != staticWidths) {
- ckfree((char *) widths);
- }
+ SetGWorld(saveWorld, saveDevice);
*lengthPtr = curX;
+ return curByte;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * BreakLine --
+ *
+ * Determine where the given line of text should be broken so that it
+ * fits in the specified range. Before calling this function, the
+ * font values and graphics port must be set.
+ *
+ * Results:
+ * The return value is NULL if the specified range is larger that the
+ * space the text needs, and *widthLeftPtr is filled with how much
+ * space is left in the range after measuring the whole text buffer.
+ * Otherwise, the return value is a pointer into the text buffer that
+ * indicates where the line should be broken (up to, but not including
+ * that character), and *widthLeftPtr is filled with how much space is
+ * left in the range after measuring up to that character.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static char *
+BreakLine(
+ FontFamily *familyPtr, /* FontFamily that describes the font values
+ * that are already selected into the graphics
+ * port. */
+ 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. */
+ 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 *widthLeftPtr) /* On input, specifies size of range into
+ * which characters from source buffer should
+ * be fit. On output, filled with how much
+ * space is left after fitting as many
+ * characters as possible into the range.
+ * Result may be negative if TK_AT_LEAST_ONE
+ * was specified in the flags argument. */
+{
+ Fixed pixelWidth, widthLeft;
+ StyledLineBreakCode breakCode;
+ Tcl_DString runString;
+ long textOffset;
+ Boolean leadingEdge;
+ Point point;
+ int charOffset, thisCharWasDoubleByte;
+ char *p, *end, *typeTable;
- SetGWorld(saveWorld, saveDevice);
+ TextFont(familyPtr->faceNum);
+ Tcl_UtfToExternalDString(familyPtr->encoding, source, numBytes,
+ &runString);
+ pixelWidth = Int2Fixed(*widthLeftPtr) + 1;
+ if (flags & TK_WHOLE_WORDS) {
+ textOffset = (flags & TK_AT_LEAST_ONE);
+ widthLeft = pixelWidth;
+ breakCode = StyledLineBreak(Tcl_DStringValue(&runString),
+ Tcl_DStringLength(&runString), 0, Tcl_DStringLength(&runString),
+ 0, &widthLeft, &textOffset);
+ if (breakCode != smBreakOverflow) {
+ /*
+ * StyledLineBreak includes all the space characters at the end of
+ * line that we want to suppress.
+ */
+
+ textOffset = VisibleLength(Tcl_DStringValue(&runString), textOffset);
+ goto getoffset;
+ }
+ } else {
+ point.v = 1;
+ point.h = 1;
+ textOffset = PixelToChar(Tcl_DStringValue(&runString),
+ Tcl_DStringLength(&runString), 0, pixelWidth, &leadingEdge,
+ &widthLeft, smOnlyStyleRun, point, point);
+ if (Fixed2Int(widthLeft) < 0) {
+ goto getoffset;
+ }
+ }
+ *widthLeftPtr = Fixed2Int(widthLeft);
+ Tcl_DStringFree(&runString);
+ return NULL;
+
+ /*
+ * The conversion routine that converts UTF-8 to the target encoding
+ * must map one UTF-8 character to exactly one encoding-specific
+ * character, so that the following algorithm works:
+ *
+ * 1. Get byte offset of where line should be broken.
+ * 2. Get char offset corresponding to that byte offset.
+ * 3. Map that char offset to byte offset in UTF-8 string.
+ */
+
+ getoffset:
+ thisCharWasDoubleByte = 0;
+ if (familyPtr->isMultiByteFont == 0) {
+ charOffset = textOffset;
+ } else {
+ charOffset = 0;
+ typeTable = familyPtr->typeTable;
+
+ p = Tcl_DStringValue(&runString);
+ end = p + textOffset;
+ thisCharWasDoubleByte = typeTable[*((unsigned char *) p)];
+ for ( ; p < end; p++) {
+ thisCharWasDoubleByte = typeTable[*((unsigned char *) p)];
+ p += thisCharWasDoubleByte;
+ charOffset++;
+ }
+ }
- return curIdx;
+ if ((flags & TK_WHOLE_WORDS) == 0) {
+ if ((flags & TK_PARTIAL_OK) && (leadingEdge != 0)) {
+ textOffset += thisCharWasDoubleByte;
+ textOffset++;
+ charOffset++;
+ } else if (((flags & TK_PARTIAL_OK) == 0) && (leadingEdge == 0)) {
+ textOffset -= thisCharWasDoubleByte;
+ textOffset--;
+ charOffset--;
+ }
+ }
+ if ((textOffset == 0) && (Tcl_DStringLength(&runString) > 0)
+ && (flags & TK_AT_LEAST_ONE)) {
+ p = Tcl_DStringValue(&runString);
+ textOffset += familyPtr->typeTable[*((unsigned char *) p)];
+ textOffset++;
+ charOffset++;
+ }
+ *widthLeftPtr = Fixed2Int(pixelWidth)
+ - TextWidth(Tcl_DStringValue(&runString), 0, textOffset);
+ Tcl_DStringFree(&runString);
+ return Tcl_UtfAtIndex(source, charOffset);
}
/*
@@ -489,14 +976,14 @@ Tk_DrawChars(
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, /* Characters to be displayed. Need not be
+ 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 numChars, /* Number of characters in string. */
+ int numBytes, /* Number of bytes in string. */
int x, int y) /* Coordinates at which to place origin of
* string when drawing. */
{
@@ -538,19 +1025,12 @@ Tk_DrawChars(
bufferPort = TkMacGetDrawablePort(pixmap);
SetGWorld(bufferPort, NULL);
- TextFont(fontPtr->family);
- TextSize(fontPtr->size);
- TextFace(fontPtr->style);
-
- if (TkSetMacColor(gc->foreground, &macColor)) {
+ if (TkSetMacColor(gc->foreground, &macColor) == true) {
RGBForeColor(&macColor);
}
-
ShowPen();
- MoveTo((short) 0, (short) 0);
FillRect(&stippleMap->bounds, &tcl_macQdPtr->white);
- MoveTo((short) x, (short) y);
- DrawText(source, 0, (short) numChars);
+ MultiFontDrawText(fontPtr, source, numBytes, 0, 0);
SetGWorld(destPort, NULL);
CopyDeepMask(&((GrafPtr) bufferPort)->portBits, stippleMap,
@@ -565,18 +1045,13 @@ Tk_DrawChars(
Tk_FreePixmap(display, pixmap);
ckfree(stippleMap->baseAddr);
ckfree((char *)stippleMap);
- } else {
- TextFont(fontPtr->family);
- TextSize(fontPtr->size);
- TextFace(fontPtr->style);
-
+ } else {
if (TkSetMacColor(gc->foreground, &macColor) == true) {
RGBForeColor(&macColor);
}
-
ShowPen();
- MoveTo((short) (macWin->xOff + x), (short) (macWin->yOff + y));
- DrawText(source, 0, (short) numChars);
+ MultiFontDrawText(fontPtr, source, numBytes, macWin->xOff + x,
+ macWin->yOff + y);
}
TextFont(txFont);
@@ -587,92 +1062,1057 @@ Tk_DrawChars(
}
/*
+ *-------------------------------------------------------------------------
+ *
+ * MultiFontDrawText --
+ *
+ * Helper function for Tk_DrawChars. Draws characters, using the
+ * various screen fonts in fontPtr to draw multilingual characters.
+ * Note: No bidirectional support.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Information gets drawn on the screen.
+ * Contents of fontPtr may be modified if more subfonts were loaded
+ * in order to draw all the multilingual characters in the given
+ * string.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+MultiFontDrawText(
+ MacFont *fontPtr, /* Contains set of fonts to use when drawing
+ * following string. */
+ CONST char *source, /* Potentially multilingual UTF-8 string. */
+ int numBytes, /* Length of string in bytes. */
+ int x, int y) /* Coordinates at which to place origin *
+ * of string when drawing. */
+{
+ FontFamily *lastFamilyPtr, *thisFamilyPtr;
+ Tcl_DString runString;
+ CONST char *p, *end, *next;
+ Tcl_UniChar ch;
+
+ TextSize(fontPtr->size);
+ TextFace(fontPtr->style);
+
+ lastFamilyPtr = fontPtr->subFontArray[0].familyPtr;
+
+ end = source + numBytes;
+ for (p = source; p < end; ) {
+ next = p + Tcl_UtfToUniChar(p, &ch);
+ thisFamilyPtr = FindSubFontForChar(fontPtr, ch)->familyPtr;
+ if (thisFamilyPtr != lastFamilyPtr) {
+ if (p > source) {
+ TextFont(lastFamilyPtr->faceNum);
+ Tcl_UtfToExternalDString(lastFamilyPtr->encoding, source,
+ p - source, &runString);
+ MoveTo((short) x, (short) y);
+ DrawText(Tcl_DStringValue(&runString), 0,
+ Tcl_DStringLength(&runString));
+ x += TextWidth(Tcl_DStringValue(&runString), 0,
+ Tcl_DStringLength(&runString));
+ Tcl_DStringFree(&runString);
+ source = p;
+ }
+ lastFamilyPtr = thisFamilyPtr;
+ }
+ p = next;
+ }
+ if (p > source) {
+ TextFont(thisFamilyPtr->faceNum);
+ Tcl_UtfToExternalDString(lastFamilyPtr->encoding, source,
+ p - source, &runString);
+ MoveTo((short) x, (short) y);
+ DrawText(Tcl_DStringValue(&runString), 0,
+ Tcl_DStringLength(&runString));
+ Tcl_DStringFree(&runString);
+ }
+}
+
+/*
*---------------------------------------------------------------------------
*
- * AllocMacFont --
+ * TkMacIsCharacterMissing --
*
- * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().
- * Allocates and intializes the memory for a new TkFont that
- * wraps the platform-specific data.
+ * Given a tkFont and a character determines whether the character has
+ * a glyph defined in the font or not. Note that this is potentially
+ * not compatible with Mac OS 8 as it looks at the font handle
+ * structure directly. Looks into the character array of the font
+ * handle to determine whether the glyph is defined or not.
*
* Results:
- * Returns pointer to newly constructed TkFont.
+ * Returns a 1 if the character is missing, a 0 if it is not.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+int
+TkMacIsCharacterMissing(
+ Tk_Font tkfont, /* The font we are looking in. */
+ unsigned int searchChar) /* The character we are looking for. */
+{
+ MacFont *fontPtr = (MacFont *) tkfont;
+ FMInput fm;
+ FontRec **fontRecHandle;
+
+ fm.family = fontPtr->subFontArray[0].familyPtr->faceNum;
+ fm.size = fontPtr->size;
+ fm.face = fontPtr->style;
+ fm.needBits = 0;
+ fm.device = 0;
+ fm.numer.h = fm.numer.v = fm.denom.h = fm.denom.v = 1;
+
+#if !defined(UNIVERSAL_INTERFACES_VERSION) || (UNIVERSAL_INTERFACES_VERSION < 0x0300)
+ fontRecHandle = (FontRec **) FMSwapFont(&fm)->fontResult;
+#else
+ fontRecHandle = (FontRec **) FMSwapFont(&fm)->fontHandle;
+#endif
+ return *(short *) ((long) &(*fontRecHandle)->owTLoc
+ + ((long)((*fontRecHandle)->owTLoc + searchChar
+ - (*fontRecHandle)->firstChar) * sizeof(short))) == -1;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * InitFont --
+ *
+ * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().
+ * Initializes the memory for a MacFont 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 MacFont structure.
+ *
* Side effects:
* Memory allocated.
*
*---------------------------------------------------------------------------
*/
-static TkFont *
-AllocMacFont(
- 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. */
+static void
+InitFont(
Tk_Window tkwin, /* For display where font will be used. */
- int family, /* Macintosh font family. */
+ int faceNum, /* Macintosh font number. */
int size, /* Point size for Macintosh font. */
- int style) /* Macintosh style bits. */
+ int style, /* Macintosh style bits. */
+ MacFont *fontPtr) /* Filled with information constructed from
+ * the above arguments. */
{
- char buf[257];
+ Str255 nativeName;
FontInfo fi;
- MacFont *fontPtr;
TkFontAttributes *faPtr;
TkFontMetrics *fmPtr;
CGrafPtr saveWorld;
GDHandle saveDevice;
+ short pixels;
- if (gWorld == NULL) {
- Rect rect = {0, 0, 1, 1};
-
- if (NewGWorld(&gWorld, 0, &rect, NULL, NULL, 0) != noErr) {
- panic("NewGWorld failed in AllocMacFont");
- }
+ if (size == 0) {
+ size = -GetDefFontSize();
}
+ pixels = (short) TkFontGetPixels(tkwin, size);
+
GetGWorld(&saveWorld, &saveDevice);
SetGWorld(gWorld, NULL);
+ TextFont(faceNum);
+ TextSize(pixels);
+ TextFace(style);
- if (tkFontPtr == NULL) {
- fontPtr = (MacFont *) ckalloc(sizeof(MacFont));
- } else {
- fontPtr = (MacFont *) tkFontPtr;
- }
+ GetFontInfo(&fi);
+ GetFontName(faceNum, nativeName);
fontPtr->font.fid = (Font) fontPtr;
- faPtr = &fontPtr->font.fa;
- GetFontName(family, (StringPtr) buf);
- buf[UCHAR(buf[0]) + 1] = '\0';
- faPtr->family = Tk_GetUid(buf + 1);
- faPtr->pointsize = size;
+ faPtr = &fontPtr->font.fa;
+ faPtr->family = GetUtfFaceName(nativeName);
+ faPtr->size = TkFontGetPoints(tkwin, size);
faPtr->weight = (style & bold) ? TK_FW_BOLD : TK_FW_NORMAL;
faPtr->slant = (style & italic) ? TK_FS_ITALIC : TK_FS_ROMAN;
faPtr->underline = ((style & underline) != 0);
faPtr->overstrike = 0;
- fmPtr = &fontPtr->font.fm;
- TextFont(family);
- TextSize(size);
- TextFace(style);
- GetFontInfo(&fi);
+ fmPtr = &fontPtr->font.fm;
fmPtr->ascent = fi.ascent;
fmPtr->descent = fi.descent;
fmPtr->maxWidth = fi.widMax;
fmPtr->fixed = (CharWidth('i') == CharWidth('w'));
-
- fontPtr->family = (short) family;
- fontPtr->size = (short) size;
+
+ fontPtr->size = pixels;
fontPtr->style = (short) style;
+
+ fontPtr->numSubFonts = 1;
+ fontPtr->subFontArray = fontPtr->staticSubFonts;
+ InitSubFont(fontPtr, faceNum, &fontPtr->subFontArray[0]);
SetGWorld(saveWorld, saveDevice);
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * ReleaseFont --
+ *
+ * Called to release the Macintosh-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(
+ MacFont *fontPtr) /* The font to delete. */
+{
+ int i;
- return (TkFont *) fontPtr;
+ for (i = 0; i < fontPtr->numSubFonts; i++) {
+ ReleaseSubFont(&fontPtr->subFontArray[i]);
+ }
+ if (fontPtr->subFontArray != fontPtr->staticSubFonts) {
+ ckfree((char *) 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(
+ CONST MacFont *fontPtr, /* Font object in which the SubFont will be
+ * used. */
+ int faceNum, /* The font number. */
+ SubFont *subFontPtr) /* Filled with SubFont constructed from
+ * above attributes. */
+{
+ subFontPtr->familyPtr = AllocFontFamily(fontPtr, faceNum);
+ 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(
+ SubFont *subFontPtr) /* The SubFont to delete. */
+{
+ FreeFontFamily(subFontPtr->familyPtr);
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * AllocFontFamily --
+ *
+ * Find the FontFamily structure associated with the given font
+ * family. The information should be stored by the caller in a
+ * SubFont and used when determining if that SubFont supports a
+ * character.
+ *
+ * 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.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static FontFamily *
+AllocFontFamily(
+ CONST MacFont *fontPtr, /* Font object in which the FontFamily will
+ * be used. */
+ int faceNum) /* The font number. */
+{
+ FontFamily *familyPtr;
+ int i;
+
+ familyPtr = fontFamilyList;
+ for (; familyPtr != NULL; familyPtr = familyPtr->nextPtr) {
+ if (familyPtr->faceNum == faceNum) {
+ familyPtr->refCount++;
+ return familyPtr;
+ }
+ }
+
+ familyPtr = (FontFamily *) ckalloc(sizeof(FontFamily));
+ memset(familyPtr, 0, sizeof(FontFamily));
+ familyPtr->nextPtr = fontFamilyList;
+ fontFamilyList = familyPtr;
+
+ /*
+ * Set key for this FontFamily.
+ */
+
+ familyPtr->faceNum = faceNum;
+
+ /*
+ * 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;
+ familyPtr->encoding = GetFontEncoding(faceNum, 1, &familyPtr->isSymbolFont);
+ familyPtr->isMultiByteFont = 0;
+ FillParseTable(familyPtr->typeTable, FontToScript(faceNum));
+ for (i = 0; i < 256; i++) {
+ if (familyPtr->typeTable[i] != 0) {
+ familyPtr->isMultiByteFont = 1;
+ break;
+ }
+ }
+ return familyPtr;
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * FreeFontFamily --
+ *
+ * Called to free a 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;
+ 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((char *) familyPtr->fontMap[i]);
+ }
+ }
+
+ /*
+ * Delete from list.
+ */
+
+ for (familyPtrPtr = &fontFamilyList; ; ) {
+ if (*familyPtrPtr == familyPtr) {
+ *familyPtrPtr = familyPtr->nextPtr;
+ break;
+ }
+ familyPtrPtr = &(*familyPtrPtr)->nextPtr;
+ }
+
+ ckfree((char *) familyPtr);
}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * FindSubFontForChar --
+ *
+ * Determine which physical 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.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static SubFont *
+FindSubFontForChar(
+ MacFont *fontPtr, /* The font object with which the character
+ * will be displayed. */
+ int ch) /* The Unicode character to be displayed. */
+{
+ int i, j, k;
+ char *fallbackName;
+ char **aliases;
+ SubFont *subFontPtr;
+ FontNameMap *mapPtr;
+ Tcl_DString faceNames;
+ char ***fontFallbacks;
+ char **anyFallbacks;
+
+ 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];
+ }
+ }
+ /*
+ * 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(&faceNames);
+
+ aliases = TkFontGetAliasList(fontPtr->font.fa.family);
+
+ subFontPtr = NULL;
+ fontFallbacks = TkFontGetFallbacks();
+ for (i = 0; fontFallbacks[i] != NULL; i++) {
+ for (j = 0; fontFallbacks[i][j] != NULL; j++) {
+ fallbackName = fontFallbacks[i][j];
+ if (strcasecmp(fallbackName, fontPtr->font.fa.family) == 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(aliases[k], fallbackName) == 0) {
+ goto tryfallbacks;
+ }
+ }
+ }
+ }
+ continue;
+
+ /*
+ * ...then see if we can use one of the fallbacks, or an
+ * alias for one of the fallbacks.
+ */
+
+ tryfallbacks:
+ for (j = 0; fontFallbacks[i][j] != NULL; j++) {
+ fallbackName = fontFallbacks[i][j];
+ subFontPtr = CanUseFallbackWithAliases(fontPtr, fallbackName,
+ ch, &faceNames);
+ if (subFontPtr != NULL) {
+ goto end;
+ }
+ }
+ }
+
+ /*
+ * See if we can use something from the global fallback list.
+ */
+
+ anyFallbacks = TkFontGetGlobalClass();
+ for (i = 0; anyFallbacks[i] != NULL; i++) {
+ fallbackName = anyFallbacks[i];
+ subFontPtr = CanUseFallbackWithAliases(fontPtr, fallbackName, ch,
+ &faceNames);
+ if (subFontPtr != NULL) {
+ goto end;
+ }
+ }
+
+ /*
+ * Try all face names available in the whole system until we
+ * find one that can be used.
+ */
+
+ for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) {
+ fallbackName = mapPtr->utfName;
+ if (SeenName(fallbackName, &faceNames) == 0) {
+ subFontPtr = CanUseFallback(fontPtr, fallbackName, ch);
+ if (subFontPtr != NULL) {
+ goto end;
+ }
+ }
+ }
+
+ end:
+ Tcl_DStringFree(&faceNames);
+
+ if (subFontPtr == NULL) {
+ /*
+ * No font can display this character. We will use the base font
+ * and have it display the "unknown" character.
+ */
+
+ subFontPtr = &fontPtr->subFontArray[0];
+ 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 HFONT can (1) or cannot (0) display the
+ * characters on the page.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Mempry 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. */
+{
+ FMInput fm;
+ FontRec *fontRecPtr;
+ short *widths;
+ int i, end, bitOffset, isMultiByteFont;
+ char src[TCL_UTF_MAX];
+ unsigned char buf[16];
+ int srcRead, dstWrote;
+ Tcl_Encoding encoding;
+
+ subFontPtr->fontMap[row] = (char *) ckalloc(FONTMAP_BITSPERPAGE / 8);
+ memset(subFontPtr->fontMap[row], 0, FONTMAP_BITSPERPAGE / 8);
+
+ encoding = subFontPtr->familyPtr->encoding;
+
+ fm.family = subFontPtr->familyPtr->faceNum;
+ fm.size = 12;
+ fm.face = 0;
+ fm.needBits = 0;
+ fm.device = 0;
+ fm.numer.h = 1;
+ fm.numer.v = 1;
+ fm.denom.h = 1;
+ fm.denom.v = 1;
+
+#if !defined(UNIVERSAL_INTERFACES_VERSION) || (UNIVERSAL_INTERFACES_VERSION < 0x0300)
+ fontRecPtr = *((FontRec **) FMSwapFont(&fm)->fontResult);
+#else
+ fontRecPtr = *((FontRec **) FMSwapFont(&fm)->fontHandle);
+#endif
+ widths = (short *) ((long) &fontRecPtr->owTLoc
+ + ((long) (fontRecPtr->owTLoc - fontRecPtr->firstChar)
+ * sizeof(short)));
+ isMultiByteFont = subFontPtr->familyPtr->isMultiByteFont;
+
+ end = (row + 1) << FONTMAP_SHIFT;
+ for (i = row << FONTMAP_SHIFT; i < end; i++) {
+ if (Tcl_UtfToExternal(NULL, encoding, src, Tcl_UniCharToUtf(i, src),
+ TCL_ENCODING_STOPONERROR, NULL, (char *) buf, sizeof(buf),
+ &srcRead, &dstWrote, NULL) == TCL_OK) {
+
+ if (((isMultiByteFont != 0) && (buf[0] > 31))
+ || (widths[buf[0]] != -1)) {
+ if ((buf[0] == 0x11) && (widths[0x12] == -1)) {
+ continue;
+ }
+
+ /*
+ * Mac's char existence metrics are only for one-byte
+ * characters. If we have a double-byte char, just
+ * assume that the font supports that char if the font's
+ * encoding supports that char.
+ */
+
+ 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.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static SubFont *
+CanUseFallbackWithAliases(
+ MacFont *fontPtr, /* The font object that will own the new
+ * screen font. */
+ 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 *subFontPtr;
+ char **aliases;
+ int i;
+
+ if (SeenName(faceName, nameTriedPtr) == 0) {
+ subFontPtr = CanUseFallback(fontPtr, faceName, ch);
+ 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);
+ 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, (char *) name, (int) (strlen(name) + 1));
+ return 0;
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * CanUseFallback --
+ *
+ * If the specified physical screen font has not already been loaded
+ * into the font object, determine if the specified physical 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
+ * font name. NULL is returned if the font object already holds
+ * a reference to the specified physical font or if the specified
+ * physical font cannot display the given character.
+ *
+ * Side effects:
+ * The font object's subFontArray is updated to contain a reference
+ * to the newly allocated SubFont.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static SubFont *
+CanUseFallback(
+ MacFont *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. */
+{
+ int i;
+ SubFont subFont;
+ short faceNum;
+
+ if (GetFamilyNum(faceName, &faceNum) == 0) {
+ return NULL;
+ }
+
+ /*
+ * Skip all fonts we've already used.
+ */
+
+ for (i = 0; i < fontPtr->numSubFonts; i++) {
+ if (faceNum == fontPtr->subFontArray[i].familyPtr->faceNum) {
+ return NULL;
+ }
+ }
+
+ /*
+ * Load this font and see if it has the desired character.
+ */
+
+ InitSubFont(fontPtr, faceNum, &subFont);
+ if (((ch < 256) && (subFont.familyPtr->isSymbolFont))
+ || (FontMapLookup(&subFont, ch) == 0)) {
+ ReleaseSubFont(&subFont);
+ return NULL;
+ }
+
+ if (fontPtr->numSubFonts >= SUBFONT_SPACE) {
+ SubFont *newPtr;
+
+ newPtr = (SubFont *) ckalloc(sizeof(SubFont)
+ * (fontPtr->numSubFonts + 1));
+ memcpy((char *) newPtr, fontPtr->subFontArray,
+ fontPtr->numSubFonts * sizeof(SubFont));
+ if (fontPtr->subFontArray != fontPtr->staticSubFonts) {
+ ckfree((char *) fontPtr->subFontArray);
+ }
+ fontPtr->subFontArray = newPtr;
+ }
+ fontPtr->subFontArray[fontPtr->numSubFonts] = subFont;
+ fontPtr->numSubFonts++;
+ return &fontPtr->subFontArray[fontPtr->numSubFonts - 1];
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * GetFamilyNum --
+ *
+ * Determines if any physical screen font exists on the system with
+ * the given family name. If the family exists, then it should be
+ * possible to construct some physical screen font with that family
+ * name.
+ *
+ * Results:
+ * The return value is 0 if the specified font family does not exist,
+ * non-zero otherwise. *faceNumPtr is filled with the unique face
+ * number that identifies the screen font, or 0 if the font family
+ * did not exist.
+ *
+ * Side effects:
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static int
+GetFamilyNum(
+ CONST char *faceName, /* UTF-8 name of font family to query. */
+ short *faceNumPtr) /* Filled with font number for above family. */
+{
+ FontNameMap *mapPtr;
+
+ if (faceName != NULL) {
+ for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) {
+ if (strcasecmp(faceName, mapPtr->utfName) == 0) {
+ *faceNumPtr = mapPtr->faceNum;
+ return 1;
+ }
+ }
+ }
+ *faceNumPtr = 0;
+ return 0;
+}
+
+static int
+GetFamilyOrAliasNum(
+ CONST char *faceName, /* UTF-8 name of font family to query. */
+ short *faceNumPtr) /* Filled with font number for above family. */
+{
+ char **aliases;
+ int i;
+
+ if (GetFamilyNum(faceName, faceNumPtr) != 0) {
+ return 1;
+ }
+ aliases = TkFontGetAliasList(faceName);
+ if (aliases != NULL) {
+ for (i = 0; aliases[i] != NULL; i++) {
+ if (GetFamilyNum(aliases[i], faceNumPtr) != 0) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * GetUtfFaceName --
+ *
+ * Given the native name for a Macintosh font (in which the name of
+ * the font is in the encoding of the font itself), return the UTF-8
+ * name that corresponds to that font. The specified font name must
+ * refer to a font that actually exists on the machine.
+ *
+ * This function is used to obtain the UTF-8 name when querying the
+ * properties of a Macintosh font object.
+ *
+ * Results:
+ * The return value is a pointer to the UTF-8 of the specified font.
+ *
+ * Side effects:
+ * None.
+ *
+ *------------------------------------------------------------------------
+ */
+
+static Tk_Uid
+GetUtfFaceName(
+ StringPtr nativeName) /* Pascal name for font in native encoding. */
+{
+ FontNameMap *mapPtr;
+
+ for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) {
+ if (pstrcmp(nativeName, mapPtr->nativeName) == 0) {
+ return mapPtr->utfName;
+ }
+ }
+ panic("GetUtfFaceName: unexpected nativeName");
+ return NULL;
+}
+
+/*
+ *------------------------------------------------------------------------
+ *
+ * GetFontEncoding --
+ *
+ * Return a string that can be passed to Tcl_GetTextEncoding() and
+ * used to convert bytes from UTF-8 into the encoding of the
+ * specified font.
+ *
+ * The desired encoding to use to convert the name of a symbolic
+ * font into UTF-8 is macRoman, while the desired encoding to use
+ * to convert bytes in a symbolic font to UTF-8 is the corresponding
+ * symbolic encoding. Due to this dual interpretatation of symbolic
+ * fonts, the caller can specify what type of encoding to return
+ * should the specified font be symbolic.
+ *
+ * Results:
+ * The return value is a string that specifies the font's encoding.
+ * If the font's encoding could not be identified, NULL is returned.
+ *
+ * Side effects:
+ * None.
+ *
+ *------------------------------------------------------------------------
+ */
+
+static Tcl_Encoding
+GetFontEncoding(
+ int faceNum, /* Macintosh font number. */
+ int allowSymbol, /* If non-zero, then the encoding string
+ * for symbol fonts will be the corresponding
+ * symbol encoding. Otherwise, the encoding
+ * string for symbol fonts will be
+ * "macRoman". */
+ int *isSymbolPtr) /* Filled with non-zero if this font is a
+ * symbol font, 0 otherwise. */
+{
+ Str255 faceName;
+ int script, lang;
+ char *name;
+
+ if (allowSymbol != 0) {
+ GetFontName(faceNum, faceName);
+ if (pstrcasecmp(faceName, "\psymbol") == 0) {
+ *isSymbolPtr = 1;
+ return Tcl_GetEncoding(NULL, "symbol");
+ }
+ if (pstrcasecmp(faceName, "\pzapf dingbats") == 0) {
+ *isSymbolPtr = 1;
+ return Tcl_GetEncoding(NULL, "macDingbats");
+ }
+ }
+
+ *isSymbolPtr = 0;
+
+ script = FontToScript(faceNum);
+ lang = GetScriptVariable(script, smScriptLang);
+ name = NULL;
+ if (script == smRoman) {
+ name = TkFindStateString(romanMap, lang);
+ } else if (script == smCyrillic) {
+ name = TkFindStateString(cyrillicMap, lang);
+ }
+ if (name == NULL) {
+ name = TkFindStateString(scriptMap, script);
+ }
+ return Tcl_GetEncoding(NULL, name);
+}