tkMacOSXFont.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:65k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tkMacOSXFont.c --
  3.  *
  4.  * Contains the Macintosh implementation of the platform-independant
  5.  * font package interface.
  6.  *
  7.  * Copyright (c) 1990-1994 The Regents of the University of California.
  8.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  9.  * Copyright 2001, Apple Computer, Inc.
  10.  * Copyright (c) 2006-2007 Daniel A. Steffen <das@users.sourceforge.net>
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  *
  15.  * RCS: @(#) $Id: tkMacOSXFont.c,v 1.3.2.11 2007/11/09 06:26:55 das Exp $
  16.  */
  17. #include "tkMacOSXPrivate.h"
  18. #include "tkMacOSXFont.h"
  19. #include "tclInt.h" /* for Tcl_CreateNamespace() */
  20. /*
  21.  * Dealing with pascal strings.
  22.  */
  23. #ifndef StrLength
  24. #define StrLength(s)  (*((unsigned char *) (s)))
  25. #endif
  26. #ifndef StrBody
  27. #define StrBody(s) ((char *) (s) + 1)
  28. #endif
  29. #define pstrcmp(s1, s2) RelString((s1), (s2), 1, 1)
  30. #define pstrcasecmp(s1, s2) RelString((s1), (s2), 0, 1)
  31. /*
  32.  * The preferred font encodings.
  33.  */
  34. static const char *encodingList[] = {
  35.     "macRoman", "macJapan", NULL
  36. };
  37. /*
  38.  * The following structures are used to map the script/language codes of a
  39.  * font to the name that should be passed to Tcl_GetTextEncoding() to obtain
  40.  * the encoding for that font. The set of numeric constants is fixed and
  41.  * defined by Apple.
  42.  */
  43. static TkStateMap scriptMap[] = {
  44.     {smRoman, "macRoman"},
  45.     {smJapanese, "macJapan"},
  46.     {smTradChinese, "macChinese"},
  47.     {smKorean, "macKorean"},
  48.     {smArabic, "macArabic"},
  49.     {smHebrew, "macHebrew"},
  50.     {smGreek, "macGreek"},
  51.     {smCyrillic, "macCyrillic"},
  52.     {smRSymbol, "macRSymbol"},
  53.     {smDevanagari, "macDevanagari"},
  54.     {smGurmukhi, "macGurmukhi"},
  55.     {smGujarati, "macGujarati"},
  56.     {smOriya, "macOriya"},
  57.     {smBengali, "macBengali"},
  58.     {smTamil, "macTamil"},
  59.     {smTelugu, "macTelugu"},
  60.     {smKannada, "macKannada"},
  61.     {smMalayalam, "macMalayalam"},
  62.     {smSinhalese, "macSinhalese"},
  63.     {smBurmese, "macBurmese"},
  64.     {smKhmer, "macKhmer"},
  65.     {smThai, "macThailand"},
  66.     {smLaotian, "macLaos"},
  67.     {smGeorgian, "macGeorgia"},
  68.     {smArmenian, "macArmenia"},
  69.     {smSimpChinese, "macSimpChinese"},
  70.     {smTibetan, "macTIbet"},
  71.     {smMongolian, "macMongolia"},
  72.     {smGeez, "macEthiopia"},
  73.     {smEastEurRoman, "macCentEuro"},
  74.     {smVietnamese, "macVietnam"},
  75.     {smExtArabic, "macSindhi"},
  76.     {0, NULL}
  77. };
  78. static TkStateMap romanMap[] = {
  79.     {langCroatian,   "macCroatian"},
  80.     {langSlovenian,   "macCroatian"},
  81.     {langIcelandic,   "macIceland"},
  82.     {langRomanian,   "macRomania"},
  83.     {langTurkish,   "macTurkish"},
  84.     {langGreek,   "macGreek"},
  85.     {0,   NULL}
  86. };
  87. static TkStateMap cyrillicMap[] = {
  88.     {langUkrainian,    "macUkraine"},
  89.     {langBulgarian,    "macBulgaria"},
  90.     {0,    NULL}
  91. };
  92. /*
  93.  * The following structure represents a font family.  It is assumed that
  94.  * all screen fonts constructed from the same "font family" share certain
  95.  * properties; all screen fonts with the same "font family" point to a
  96.  * shared instance of this structure.  The most important shared property
  97.  * is the character existence metrics, used to determine if a screen font
  98.  * can display a given Unicode character.
  99.  *
  100.  * Under Macintosh, a "font family" is uniquely identified by its face number.
  101.  */
  102. #define FONTMAP_SHIFT    10
  103. #define FONTMAP_PAGES    (1 << (sizeof(Tcl_UniChar) * 8 - FONTMAP_SHIFT))
  104. #define FONTMAP_BITSPERPAGE    (1 << FONTMAP_SHIFT)
  105. typedef struct FontFamily {
  106.     struct FontFamily *nextPtr;  /* Next in list of all known font families. */
  107.     int refCount;  /* How many SubFonts are referring to this
  108.   * FontFamily. When the refCount drops to
  109.   * zero, this FontFamily may be freed. */
  110.     /*
  111.      * Key.
  112.      */
  113.     FMFontFamily faceNum; /* Unique face number key for this FontFamily. */
  114.     /*
  115.      * Derived properties.
  116.      */
  117.     Tcl_Encoding encoding; /* Encoding for this font family. */
  118.     int isSymbolFont; /* Non-zero if this is a symbol family. */
  119.     int isMultiByteFont; /* Non-zero if this is a multi-byte family. */
  120.     char typeTable[256]; /* Table that identfies all lead bytes for a
  121.  * multi-byte family, used when measuring chars.
  122.  * If a byte is a lead byte, the value at the
  123.  * corresponding position in the typeTable is 1,
  124.  * otherwise 0. If this is a single-byte font,
  125.  * all entries are 0. */
  126.     char *fontMap[FONTMAP_PAGES];
  127. /* Two-level sparse table used to determine
  128.  * quickly if the specified character exists.
  129.  * As characters are encountered, more pages
  130.  * in this table are dynamically added. The
  131.  * contents of each page is a bitmask
  132.  * consisting of FONTMAP_BITSPERPAGE bits,
  133.  * representing whether this font can be used
  134.  * to display the given character at the
  135.  * corresponding bit position. The high bits
  136.  * of the character are used to pick which
  137.  * page of the table is used. */
  138. } FontFamily;
  139. /*
  140.  * The following structure encapsulates an individual screen font.  A font
  141.  * object is made up of however many SubFonts are necessary to display a
  142.  * stream of multilingual characters.
  143.  */
  144. typedef struct SubFont {
  145.     char **fontMap; /* Pointer to font map from the FontFamily,
  146.  * cached here to save a dereference. */
  147.     FontFamily *familyPtr; /* The FontFamily for this SubFont. */
  148. } SubFont;
  149. /*
  150.  * The following structure represents Macintosh's implementation of a font
  151.  * object.
  152.  */
  153. #define SUBFONT_SPACE 3
  154. typedef struct MacFont {
  155.     TkFont font; /* Stuff used by generic font package. Must
  156.  * be first in structure. */
  157.     SubFont staticSubFonts[SUBFONT_SPACE];
  158. /* Builtin space for a limited number of
  159.  * SubFonts. */
  160.     int numSubFonts; /* Length of following array. */
  161.     SubFont *subFontArray; /* Array of SubFonts that have been loaded
  162.  * in order to draw/measure all the characters
  163.  * encountered by this font so far.  All fonts
  164.  * start off with one SubFont initialized by
  165.  * AllocFont() from the original set of font
  166.  * attributes. Usually points to
  167.  * staticSubFonts, but may point to malloced
  168.  * space if there are lots of SubFonts. */
  169.     short size; /* Font size in pixels, constructed from
  170.  * font attributes. */
  171.     short style; /* Style bits, constructed from font
  172.  * attributes. */
  173. } MacFont;
  174. /*
  175.  * The following structure is used to map between the UTF-8 name for a font and
  176.  * the name that the Macintosh uses to refer to the font, in order to determine
  177.  * if a font exists.  The Macintosh names for fonts are stored in the encoding
  178.  * of the font itself.
  179.  */
  180. typedef struct FontNameMap {
  181.     Tk_Uid utfName; /* The name of the font in UTF-8. */
  182.     StringPtr nativeName; /* The name of the font in the font's encoding. */
  183.     FMFontFamily faceNum; /* Unique face number for this font. */
  184. } FontNameMap;
  185. /*
  186.  * The list of font families that are currently loaded. As screen fonts
  187.  * are loaded, this list grows to hold information about what characters
  188.  * exist in each font family.
  189.  */
  190. static FontFamily *fontFamilyList = NULL;
  191. /*
  192.  * Information cached about the system at startup time.
  193.  */
  194. static FontNameMap *gFontNameMap = NULL;
  195. static GWorldPtr gWorld = NULL;
  196. /*
  197.  * The names for our "native" fonts.
  198.  */
  199. #define SYSTEMFONT_NAME "system"
  200. #define APPLFONT_NAME "application"
  201. #define MENUITEMFONT_NAME "menu"
  202. /*
  203.  * Procedures used only in this file.
  204.  */
  205. static FontFamily * AllocFontFamily(const MacFont *fontPtr, int family);
  206. static SubFont * CanUseFallback(MacFont *fontPtr, const char *fallbackName, int ch, SubFont **fixSubFontPtrPtr);
  207. static SubFont * CanUseFallbackWithAliases(MacFont *fontPtr, const char *faceName, int ch, Tcl_DString *nameTriedPtr, SubFont **fixSubFontPtrPtr);
  208. static SubFont * FindSubFontForChar(MacFont *fontPtr, int ch, SubFont **fixSubFontPtrPtr);
  209. static void FontMapInsert(SubFont *subFontPtr, int ch);
  210. static void FontMapLoadPage(SubFont *subFontPtr, int row);
  211. static int  FontMapLookup(SubFont *subFontPtr, int ch);
  212. static void FreeFontFamily(FontFamily *familyPtr);
  213. static void InitFont(Tk_Window tkwin, int family, unsigned char *familyName, int size, int style, MacFont *fontPtr);
  214. static void InitSubFont(const MacFont *fontPtr, int family, SubFont *subFontPtr);
  215. static void MultiFontDrawText(MacFont *fontPtr, const char *source, int numBytes, int x, int y);
  216. static void ReleaseFont(MacFont *fontPtr);
  217. static void ReleaseSubFont(SubFont *subFontPtr);
  218. static int SeenName(const char *name, Tcl_DString *dsPtr);
  219. static const char * BreakLine(FontFamily *familyPtr, int flags, const char *source, int numBytes, int *widthPtr);
  220. static int GetFamilyNum(const char *faceName, short *familyPtr);
  221. static int GetFamilyOrAliasNum(const char *faceName, short *familyPtr);
  222. static Tcl_Encoding GetFontEncoding(int faceNum, int allowSymbol, int *isSymbolPtr);
  223. static Tk_Uid GetUtfFaceName(StringPtr faceNameStr);
  224. static OSStatus GetThemeFontAndFamily(const ThemeFontID themeFontId,
  225. FMFontFamily *fontFamily, unsigned char *fontName, SInt16 *fontSize,
  226. Style *fontStyle);
  227. /*
  228.  *-------------------------------------------------------------------------
  229.  *
  230.  * TkpFontPkgInit --
  231.  *
  232.  * This procedure is called when an application is created. It
  233.  * initializes all the structures that are used by the
  234.  * platform-dependant code on a per application basis.
  235.  *
  236.  * Results:
  237.  * None.
  238.  *
  239.  * Side effects:
  240.  * See comments below.
  241.  *
  242.  *-------------------------------------------------------------------------
  243.  */
  244. void
  245. TkpFontPkgInit(
  246.     TkMainInfo *mainPtr) /* The application being created. */
  247. {
  248.     FMFontFamilyIterator fontFamilyIterator;
  249.     FMFontFamily  fontFamily;
  250.     FontNameMap *tmpFontNameMap, *newFontNameMap, *mapPtr;
  251.     int i, j, numFonts, fontMapOffset, isSymbol;
  252.     Str255 nativeName;
  253.     Tcl_DString ds;
  254.     Tcl_Encoding encoding;
  255.     Tcl_Encoding *encodings;
  256.     if (gWorld == NULL) {
  257. Rect rect = {0, 0, 1, 1};
  258. SetFractEnable(0);
  259. /*
  260.  * Used for saving and restoring state while drawing and measuring.
  261.  */
  262. if (ChkErr(NewGWorld, &gWorld, 32, &rect, NULL, NULL, 0
  263. #ifdef __LITTLE_ENDIAN__
  264. | kNativeEndianPixMap
  265. #endif
  266. ) != noErr) {
  267.     Tcl_Panic("TkpFontPkgInit: NewGWorld failed");
  268. }
  269. /*
  270.  * The name of each font is stored in the encoding of that font.
  271.  * How would we translate a name from UTF-8 into the native encoding
  272.  * of the font unless we knew the encoding of that font?  We can't.
  273.  * So, precompute the UTF-8 and native names of all fonts on the
  274.  * system.  The when the user asks for font by its UTF-8 name, we
  275.  * lookup the name in that table and really ask for the font by its
  276.  * native name. Any unknown UTF-8 names will be mapped to the system
  277.  * font.
  278.  */
  279. FMCreateFontFamilyIterator(NULL, NULL, kFMDefaultOptions, &fontFamilyIterator);
  280. numFonts = 0;
  281. while (FMGetNextFontFamily(&fontFamilyIterator, &fontFamily) != kFMIterationCompleted) {
  282.     numFonts++;
  283. }
  284. tmpFontNameMap = (FontNameMap *) ckalloc(sizeof(FontNameMap) * numFonts);
  285. encodings = (Tcl_Encoding *) ckalloc(sizeof(Tcl_Encoding) * numFonts);
  286. mapPtr = tmpFontNameMap;
  287. FMResetFontFamilyIterator(NULL, NULL, kFMDefaultOptions, &fontFamilyIterator);
  288. i = 0;
  289. while (FMGetNextFontFamily(&fontFamilyIterator, &fontFamily) != kFMIterationCompleted) {
  290.     mapPtr->faceNum = fontFamily;
  291.     encodings[i] = GetFontEncoding(mapPtr->faceNum, 0, &isSymbol);
  292.     FMGetFontFamilyName(fontFamily, nativeName );
  293.     Tcl_ExternalToUtfDString(encodings[i], StrBody(nativeName), StrLength(nativeName), &ds);
  294.     mapPtr->utfName = Tk_GetUid(Tcl_DStringValue(&ds));
  295.     mapPtr->nativeName = (StringPtr) ckalloc(StrLength(nativeName) + 1);
  296.     memcpy(mapPtr->nativeName, nativeName, StrLength(nativeName) + 1);
  297.     Tcl_DStringFree(&ds);
  298.     mapPtr++;
  299.     i++;
  300. }
  301. FMDisposeFontFamilyIterator(&fontFamilyIterator);
  302. /*
  303.  * Reorder FontNameMap so fonts with the preferred encodings are at
  304.  * the front of the list.  The relative order of fonts that all have
  305.  * the same encoding is preserved.  Fonts with unknown encodings get
  306.  * stuck at the end.
  307.  */
  308. newFontNameMap = (FontNameMap *) ckalloc(sizeof(FontNameMap) * (numFonts + 1));
  309. fontMapOffset = 0;
  310. for (i = 0; encodingList[i] != NULL; i++) {
  311.     encoding = Tcl_GetEncoding(NULL, encodingList[i]);
  312.     if (encoding == NULL) {
  313. continue;
  314.     }
  315.     for (j = 0; j < numFonts; j++) {
  316. if (encodings[j] == encoding) {
  317.     newFontNameMap[fontMapOffset] = tmpFontNameMap[j];
  318.     fontMapOffset++;
  319.     Tcl_FreeEncoding(encodings[j]);
  320.     tmpFontNameMap[j].utfName = NULL;
  321. }
  322.     }
  323.     Tcl_FreeEncoding(encoding);
  324. }
  325. for (i = 0; i < numFonts; i++) {
  326.     if (tmpFontNameMap[i].utfName != NULL) {
  327. newFontNameMap[fontMapOffset] = tmpFontNameMap[i];
  328. fontMapOffset++;
  329. Tcl_FreeEncoding(encodings[i]);
  330.     }
  331. }
  332. if (fontMapOffset != numFonts) {
  333.     Tcl_Panic("TkpFontPkgInit: unexpected number of fonts");
  334. }
  335. mapPtr = &newFontNameMap[numFonts];
  336. mapPtr->utfName = NULL;
  337. mapPtr->nativeName = NULL;
  338. mapPtr->faceNum = 0;
  339. ckfree((char *) tmpFontNameMap);
  340. ckfree((char *) encodings);
  341. gFontNameMap = newFontNameMap;
  342.     }
  343. }
  344. /*
  345.  *---------------------------------------------------------------------------
  346.  *
  347.  * GetThemeFontAndFamily --
  348.  *
  349.  * Wrapper around the GetThemeFont and FMGetFontFamilyFromName APIs.
  350.  *
  351.  *---------------------------------------------------------------------------
  352.  */
  353. OSStatus
  354. GetThemeFontAndFamily(
  355.     const ThemeFontID themeFontId,
  356.     FMFontFamily* fontFamily,
  357.     unsigned char *fontName,
  358.     SInt16 *fontSize,
  359.     Style *fontStyle)
  360. {
  361.     OSStatus err = ChkErr(GetThemeFont, themeFontId, smSystemScript, fontName,
  362.     fontSize, fontStyle);
  363.     if (err == noErr) {
  364. *fontFamily = FMGetFontFamilyFromName(fontName);
  365. if (*fontFamily == kInvalidFontFamily) {
  366.     err = kFMInvalidFontFamilyErr;
  367.     TkMacOSXDbgMsg("FMGetFontFamilyFromName failed.");
  368. }
  369.     }
  370.     return err;
  371. }
  372. /*
  373.  *---------------------------------------------------------------------------
  374.  *
  375.  * TkpGetNativeFont --
  376.  *
  377.  * Map a platform-specific native font name to a TkFont.
  378.  *
  379.  * Results:
  380.  * The return value is a pointer to a TkFont that represents the
  381.  * native font. If a native font by the given name could not be
  382.  * found, the return value is NULL.
  383.  *
  384.  * Every call to this procedure returns a new TkFont structure, even
  385.  * if the name has already been seen before. The caller should call
  386.  * TkpDeleteFont() when the font is no longer needed.
  387.  *
  388.  * The caller is responsible for initializing the memory associated
  389.  * with the generic TkFont when this function returns and releasing
  390.  * the contents of the generics TkFont before calling TkpDeleteFont().
  391.  *
  392.  * Side effects:
  393.  * None.
  394.  *
  395.  *---------------------------------------------------------------------------
  396.  */
  397. TkFont *
  398. TkpGetNativeFont(
  399.     Tk_Window tkwin, /* For display where font will be used. */
  400.     CONST char *name) /* Platform-specific font name. */
  401. {
  402.     ThemeFontID themeFontId;
  403.     FMFontFamily fontFamily;
  404.     Str255 fontName;
  405.     SInt16 fontSize;
  406.     Style  fontStyle;
  407.     MacFont * fontPtr;
  408.     if (strcmp(name, SYSTEMFONT_NAME) == 0) {
  409. themeFontId = kThemeSystemFont;
  410.     } else if (strcmp(name, APPLFONT_NAME) == 0) {
  411. themeFontId = kThemeApplicationFont;
  412.     } else if (strcmp(name, MENUITEMFONT_NAME) == 0) {
  413. themeFontId = kThemeMenuItemFont;
  414.     } else {
  415. return NULL;
  416.     }
  417.     if (GetThemeFontAndFamily(themeFontId, &fontFamily, fontName, &fontSize,
  418.     &fontStyle) != noErr) {
  419. return NULL;
  420.     }
  421.     fontPtr = (MacFont *) ckalloc(sizeof(MacFont));
  422.     InitFont(tkwin, fontFamily, fontName, fontSize, fontStyle, fontPtr);
  423.     return (TkFont *) fontPtr;
  424. }
  425. /*
  426.  *---------------------------------------------------------------------------
  427.  *
  428.  * TkpGetFontFromAttributes --
  429.  *
  430.  * Given a desired set of attributes for a font, find a font with the
  431.  * closest matching attributes.
  432.  *
  433.  * Results:
  434.  * The return value is a pointer to a TkFont that represents the font
  435.  * with the desired attributes. If a font with the desired attributes
  436.  * could not be constructed, some other font will be substituted
  437.  * automatically.
  438.  *
  439.  * Every call to this procedure returns a new TkFont structure, even
  440.  * if the specified attributes have already been seen before. The
  441.  * caller should call TkpDeleteFont() to free the platform- specific
  442.  * data when the font is no longer needed.
  443.  *
  444.  * The caller is responsible for initializing the memory associated
  445.  * with the generic TkFont when this function returns and releasing
  446.  * the contents of the generic TkFont before calling TkpDeleteFont().
  447.  *
  448.  * Side effects:
  449.  * None.
  450.  *
  451.  *---------------------------------------------------------------------------
  452.  */
  453. TkFont *
  454. TkpGetFontFromAttributes(
  455.     TkFont *tkFontPtr, /* If non-NULL, store the information in this
  456.  * existing TkFont structure, rather than
  457.  * allocating a new structure to hold the
  458.  * font; the existing contents of the font
  459.  * will be released. If NULL, a new TkFont
  460.  * structure is allocated. */
  461.     Tk_Window tkwin, /* For display where font will be used. */
  462.     CONST TkFontAttributes *faPtr)
  463. /* Set of attributes to match. */
  464. {
  465.     short faceNum, style;
  466.     int i, j;
  467.     const char *faceName, *fallback;
  468.     char ***fallbacks;
  469.     MacFont *fontPtr;
  470.     /*
  471.      * Algorithm to get the closest font to the one requested.
  472.      *
  473.      * try fontname
  474.      * try all aliases for fontname
  475.      * foreach fallback for fontname
  476.      *   try the fallback
  477.      *   try all aliases for the fallback
  478.      */
  479.     faceNum = 0;
  480.     faceName = faPtr->family;
  481.     if (faceName != NULL) {
  482. if (GetFamilyOrAliasNum(faceName, &faceNum) != 0) {
  483.     goto found;
  484. }
  485. fallbacks = TkFontGetFallbacks();
  486. for (i = 0; fallbacks[i] != NULL; i++) {
  487.     for (j = 0; (fallback = fallbacks[i][j]) != NULL; j++) {
  488. if (strcasecmp(faceName, fallback) == 0) {
  489.     for (j = 0; (fallback = fallbacks[i][j]) != NULL; j++) {
  490. if (GetFamilyOrAliasNum(fallback, &faceNum)) {
  491.     goto found;
  492. }
  493.     }
  494. }
  495. break;
  496.     }
  497. }
  498.     }
  499. found:
  500.     style = 0;
  501.     if (faPtr->weight != TK_FW_NORMAL) {
  502. style |= bold;
  503.     }
  504.     if (faPtr->slant != TK_FS_ROMAN) {
  505. style |= italic;
  506.     }
  507.     if (faPtr->underline) {
  508. style |= underline;
  509.     }
  510.     if (tkFontPtr == NULL) {
  511. fontPtr = (MacFont *) ckalloc(sizeof(MacFont));
  512.     } else {
  513. fontPtr = (MacFont *) tkFontPtr;
  514. ReleaseFont(fontPtr);
  515.     }
  516.     InitFont(tkwin, faceNum, NULL, faPtr->size, style, fontPtr);
  517.     return (TkFont *) fontPtr;
  518. }
  519. /*
  520.  *---------------------------------------------------------------------------
  521.  *
  522.  * TkpDeleteFont --
  523.  *
  524.  * Called to release a font allocated by TkpGetNativeFont() or
  525.  * TkpGetFontFromAttributes(). The caller should have already
  526.  * released the fields of the TkFont that are used exclusively by the
  527.  * generic TkFont code.
  528.  *
  529.  * Results:
  530.  * TkFont is deallocated.
  531.  *
  532.  * Side effects:
  533.  * None.
  534.  *
  535.  *---------------------------------------------------------------------------
  536.  */
  537. void
  538. TkpDeleteFont(
  539.     TkFont *tkFontPtr) /* Token of font to be deleted. */
  540. {
  541.     ReleaseFont((MacFont *) tkFontPtr);
  542. }
  543. /*
  544.  *---------------------------------------------------------------------------
  545.  *
  546.  * TkpGetFontFamilies --
  547.  *
  548.  * Return information about the font families that are available on
  549.  * the display of the given window.
  550.  *
  551.  * Results:
  552.  * Modifies interp's result object to hold a list of all the available
  553.  * font families.
  554.  *
  555.  * Side effects:
  556.  * None.
  557.  *
  558.  *---------------------------------------------------------------------------
  559.  */
  560. void
  561. TkpGetFontFamilies(
  562.     Tcl_Interp *interp, /* Interp to hold result. */
  563.     Tk_Window tkwin) /* For display to query. */
  564. {
  565.     FontNameMap *mapPtr;
  566.     Tcl_Obj *resultPtr, *strPtr;
  567.     resultPtr = Tcl_GetObjResult(interp);
  568.     for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) {
  569. strPtr = Tcl_NewStringObj(mapPtr->utfName, -1);
  570. Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);
  571.     }
  572. }
  573. /*
  574.  *-------------------------------------------------------------------------
  575.  *
  576.  * TkpGetSubFonts --
  577.  *
  578.  * A function used by the testing package for querying the actual
  579.  * screen fonts that make up a font object.
  580.  *
  581.  * Results:
  582.  * Modifies interp's result object to hold a list containing the names
  583.  * of the screen fonts that make up the given font object.
  584.  *
  585.  * Side effects:
  586.  * None.
  587.  *
  588.  *-------------------------------------------------------------------------
  589.  */
  590. void
  591. TkpGetSubFonts(
  592.     Tcl_Interp *interp, /* Interp to hold result. */
  593.     Tk_Font tkfont) /* Font object to query. */
  594. {
  595.     int i;
  596.     Tcl_Obj *resultPtr, *strPtr;
  597.     MacFont *fontPtr;
  598.     FontFamily *familyPtr;
  599.     Str255 nativeName;
  600.     resultPtr = Tcl_GetObjResult(interp);
  601.     fontPtr = (MacFont *) tkfont;
  602.     for (i = 0; i < fontPtr->numSubFonts; i++) {
  603. familyPtr = fontPtr->subFontArray[i].familyPtr;
  604.     GetFontName(familyPtr->faceNum, nativeName);
  605. strPtr = Tcl_NewStringObj(GetUtfFaceName(nativeName), -1);
  606. Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);
  607.     }
  608. }
  609. /*
  610.  *---------------------------------------------------------------------------
  611.  *
  612.  *  Tk_MeasureChars --
  613.  *
  614.  * Determine the number of characters from the string that will fit
  615.  * in the given horizontal span. The measurement is done under the
  616.  * assumption that Tk_DrawChars() will be used to actually display
  617.  * the characters.
  618.  *
  619.  * Results:
  620.  * The return value is the number of bytes from source that
  621.  * fit into the span that extends from 0 to maxLength. *lengthPtr is
  622.  * filled with the x-coordinate of the right edge of the last
  623.  * character that did fit.
  624.  *
  625.  * Side effects:
  626.  * None.
  627.  *
  628.  *---------------------------------------------------------------------------
  629.  */
  630. int
  631. Tk_MeasureChars(
  632.     Tk_Font tkfont, /* Font in which characters will be drawn. */
  633.     CONST char *source, /* UTF-8 string to be displayed.  Need not be
  634.  * '' terminated. */
  635.     int numBytes, /* Maximum number of bytes to consider
  636.  * from source string. */
  637.     int maxLength, /* If >= 0, maxLength specifies the longest
  638.  * permissible line length; don't consider any
  639.  * character that would cross this
  640.  * x-position. If < 0, then line length is
  641.  * unbounded and the flags argument is
  642.  * ignored. */
  643.     int flags, /* Various flag bits OR-ed together:
  644.  * TK_PARTIAL_OK means include the last char
  645.  * which only partially fit on this line.
  646.  * TK_WHOLE_WORDS means stop on a word
  647.  * boundary, if possible.
  648.  * TK_AT_LEAST_ONE means return at least one
  649.  * character even if no characters fit. */
  650.     int *lengthPtr) /* Filled with x-location just after the
  651.  * terminating character. */
  652. {
  653.     MacFont *fontPtr;
  654.     SubFont *thisSubFontPtr, *lastSubFontPtr;
  655.     CGrafPtr savePort;
  656.     Boolean portChanged;
  657.     int curX, curByte;
  658.     /*
  659.      * According to "Inside Macintosh: Text", the Macintosh may
  660.      * automatically substitute
  661.      * ligatures or context-sensitive presentation forms when
  662.      * measuring/displaying text within a font run.  We cannot safely
  663.      * measure individual characters and add up the widths w/o errors.
  664.      * However, if we convert a range of text from UTF-8 to, say,
  665.      * Shift-JIS, and get the offset into the Shift-JIS string as to
  666.      * where a word or line break would occur, then can we map that
  667.      * number back to UTF-8?
  668.      */
  669.     fontPtr = (MacFont *) tkfont;
  670.     portChanged = QDSwapPort(gWorld, &savePort);
  671.     TextSize(fontPtr->size);
  672.     TextFace(fontPtr->style);
  673.     lastSubFontPtr = &fontPtr->subFontArray[0];
  674.     if (numBytes == 0) {
  675. curX = 0;
  676. curByte = 0;
  677.     } else if (maxLength < 0) {
  678. const char *p, *end, *next;
  679. Tcl_UniChar ch;
  680. FontFamily *familyPtr;
  681. Tcl_DString runString;
  682. /*
  683.  * A three step process:
  684.  * 1. Find a contiguous range of characters that can all be
  685.  *    represented by a single screen font.
  686.  * 2. Convert those chars to the encoding of that font.
  687.  * 3. Measure converted chars.
  688.  */
  689. curX = 0;
  690. end = source + numBytes;
  691. for (p = source; p < end; ) {
  692.     next = p + Tcl_UtfToUniChar(p, &ch);
  693.     thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
  694.     if (thisSubFontPtr != lastSubFontPtr) {
  695. familyPtr = lastSubFontPtr->familyPtr;
  696. TextFont(familyPtr->faceNum);
  697. Tcl_UtfToExternalDString(familyPtr->encoding, source,
  698. p - source, &runString);
  699. curX += TextWidth(Tcl_DStringValue(&runString), 0,
  700. Tcl_DStringLength(&runString));
  701. Tcl_DStringFree(&runString);
  702. lastSubFontPtr = thisSubFontPtr;
  703. source = p;
  704.     }
  705.     p = next;
  706. }
  707. familyPtr = lastSubFontPtr->familyPtr;
  708. TextFont(familyPtr->faceNum);
  709. Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source,
  710. &runString);
  711. curX += TextWidth(Tcl_DStringValue(&runString), 0,
  712. Tcl_DStringLength(&runString));
  713. Tcl_DStringFree(&runString);
  714. curByte = numBytes;
  715.     } else {
  716. const char *p, *end, *next, *sourceOrig;
  717. int widthLeft;
  718. Tcl_UniChar ch;
  719. const char *rest = NULL;
  720. /*
  721.  * How many chars will fit in the space allotted?
  722.  */
  723. if (maxLength > 32767) {
  724.     maxLength = 32767;
  725. }
  726. widthLeft = maxLength;
  727. sourceOrig = source;
  728. end = source + numBytes;
  729. for (p = source; p < end; p = next) {
  730.     next = p + Tcl_UtfToUniChar(p, &ch);
  731.     thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
  732.     if (thisSubFontPtr != lastSubFontPtr) {
  733. if (p > source) {
  734.     rest = BreakLine(lastSubFontPtr->familyPtr, flags, source,
  735. p - source, &widthLeft);
  736.     flags &= ~TK_AT_LEAST_ONE;
  737.     if (rest != NULL) {
  738. p = source;
  739. break;
  740.     }
  741. }
  742. lastSubFontPtr = thisSubFontPtr;
  743. source = p;
  744.     }
  745. }
  746. if (p > source) {
  747.     rest = BreakLine(lastSubFontPtr->familyPtr, flags, source, p - source,
  748. &widthLeft);
  749. }
  750. if (rest == NULL) {
  751.     curByte = numBytes;
  752. } else {
  753.     curByte = rest - sourceOrig;
  754. }
  755. curX = maxLength - widthLeft;
  756.     }
  757.     if (portChanged) {
  758. QDSwapPort(savePort, NULL);
  759.     }
  760.     *lengthPtr = curX;
  761.     return curByte;
  762. }
  763. /*
  764.  *---------------------------------------------------------------------------
  765.  *
  766.  * BreakLine --
  767.  *
  768.  * Determine where the given line of text should be broken so that it
  769.  * fits in the specified range. Before calling this function, the
  770.  * font values and graphics port must be set.
  771.  *
  772.  * Results:
  773.  * The return value is NULL if the specified range is larger that the
  774.  * space the text needs, and *widthLeftPtr is filled with how much
  775.  * space is left in the range after measuring the whole text buffer.
  776.  * Otherwise, the return value is a pointer into the text buffer that
  777.  * indicates where the line should be broken (up to, but not including
  778.  * that character), and *widthLeftPtr is filled with how much space is
  779.  * left in the range after measuring up to that character.
  780.  *
  781.  * Side effects:
  782.  * None.
  783.  *
  784.  *---------------------------------------------------------------------------
  785.  */
  786. static const char *
  787. BreakLine(
  788.     FontFamily *familyPtr, /* FontFamily that describes the font values
  789.  * that are already selected into the graphics
  790.  * port. */
  791.     int flags, /* Various flag bits OR-ed together:
  792.  * TK_PARTIAL_OK means include the last char
  793.  * which only partially fit on this line.
  794.  * TK_WHOLE_WORDS means stop on a word
  795.  * boundary, if possible.
  796.  * TK_AT_LEAST_ONE means return at least one
  797.  * character even if no characters fit. */
  798.     const char *source, /* UTF-8 string to be displayed.  Need not be
  799.  * '' terminated. */
  800.     int numBytes, /* Maximum number of bytes to consider
  801.  * from source string. */
  802.     int *widthLeftPtr) /* On input, specifies size of range into
  803.  * which characters from source buffer should
  804.  * be fit.  On output, filled with how much
  805.  * space is left after fitting as many
  806.  * characters as possible into the range.
  807.  * Result may be negative if TK_AT_LEAST_ONE
  808.  * was specified in the flags argument. */
  809. {
  810.     Fixed pixelWidth, widthLeft;
  811.     StyledLineBreakCode breakCode;
  812.     Tcl_DString runString;
  813.     long textOffset;
  814.     Boolean leadingEdge;
  815.     Point point;
  816.     int charOffset, thisCharWasDoubleByte;
  817.     char *p, *end, *typeTable;
  818.     TextFont(familyPtr->faceNum);
  819.     Tcl_UtfToExternalDString(familyPtr->encoding, source, numBytes,
  820. &runString);
  821.     pixelWidth = IntToFixed(*widthLeftPtr) + 1;
  822.     if (flags & TK_WHOLE_WORDS) {
  823. textOffset = (flags & TK_AT_LEAST_ONE);
  824. widthLeft = pixelWidth;
  825. breakCode = StyledLineBreak(Tcl_DStringValue(&runString),
  826. Tcl_DStringLength(&runString), 0, Tcl_DStringLength(&runString),
  827. 0, &widthLeft, &textOffset);
  828. if (breakCode != smBreakOverflow) {
  829.     /*
  830.      * StyledLineBreak includes all the space characters at the end of
  831.      * line that we want to suppress.
  832.      */
  833.     textOffset = VisibleLength(Tcl_DStringValue(&runString), textOffset);
  834.     goto getoffset;
  835. }
  836.     } else {
  837. point.v = 1;
  838. point.h = 1;
  839. textOffset = PixelToChar(Tcl_DStringValue(&runString),
  840. Tcl_DStringLength(&runString), 0, pixelWidth, &leadingEdge,
  841. &widthLeft, smOnlyStyleRun, point, point);
  842. if (FixedToInt(widthLeft) < 0) {
  843.     goto getoffset;
  844. }
  845.     }
  846.     *widthLeftPtr = FixedToInt(widthLeft);
  847.     Tcl_DStringFree(&runString);
  848.     return NULL;
  849.     /*
  850.      * The conversion routine that converts UTF-8 to the target encoding
  851.      * must map one UTF-8 character to exactly one encoding-specific
  852.      * character, so that the following algorithm works:
  853.      *
  854.      * 1. Get byte offset of where line should be broken.
  855.      * 2. Get char offset corresponding to that byte offset.
  856.      * 3. Map that char offset to byte offset in UTF-8 string.
  857.      */
  858.     getoffset:
  859.     thisCharWasDoubleByte = 0;
  860.     if (familyPtr->isMultiByteFont == 0) {
  861. charOffset = textOffset;
  862.     } else {
  863. charOffset = 0;
  864. typeTable = familyPtr->typeTable;
  865. p = Tcl_DStringValue(&runString);
  866. end = p + textOffset;
  867. thisCharWasDoubleByte = typeTable[*((unsigned char *) p)];
  868. for ( ; p < end; p++) {
  869.     thisCharWasDoubleByte = typeTable[*((unsigned char *) p)];
  870.     p += thisCharWasDoubleByte;
  871.     charOffset++;
  872. }
  873.     }
  874.     if ((flags & TK_WHOLE_WORDS) == 0) {
  875.     if ((flags & TK_PARTIAL_OK) && (leadingEdge != 0)) {
  876.     textOffset += thisCharWasDoubleByte;
  877.     textOffset++;
  878.     charOffset++;
  879. } else if (((flags & TK_PARTIAL_OK) == 0) && (leadingEdge == 0)) {
  880.     textOffset -= thisCharWasDoubleByte;
  881.     textOffset--;
  882.     charOffset--;
  883. }
  884.     }
  885.     if ((textOffset == 0) && (Tcl_DStringLength(&runString) > 0)
  886. && (flags & TK_AT_LEAST_ONE)) {
  887.     p = Tcl_DStringValue(&runString);
  888. textOffset += familyPtr->typeTable[*((unsigned char *) p)];
  889. textOffset++;
  890. charOffset++;
  891.     }
  892.     *widthLeftPtr = FixedToInt(pixelWidth)
  893. - TextWidth(Tcl_DStringValue(&runString), 0, textOffset);
  894.     Tcl_DStringFree(&runString);
  895.     return Tcl_UtfAtIndex(source, charOffset);
  896. }
  897. /*
  898.  *---------------------------------------------------------------------------
  899.  *
  900.  * Tk_DrawChars --
  901.  *
  902.  * Draw a string of characters on the screen.
  903.  *
  904.  * Results:
  905.  * None.
  906.  *
  907.  * Side effects:
  908.  * Information gets drawn on the screen.
  909.  *
  910.  *---------------------------------------------------------------------------
  911.  */
  912. void
  913. Tk_DrawChars(
  914.     Display *display, /* Display on which to draw. */
  915.     Drawable drawable, /* Window or pixmap in which to draw. */
  916.     GC gc, /* Graphics context for drawing characters. */
  917.     Tk_Font tkfont, /* Font in which characters will be drawn; must
  918.  * be the same as font used in GC. */
  919.     CONST char *source, /* UTF-8 string to be displayed. Need not be
  920.  * '' terminated. All Tk meta-characters
  921.  * (tabs, control characters, and newlines)
  922.  * should be stripped out of the string that
  923.  * is passed to this function. If they are not
  924.  * stripped out, they will be displayed as
  925.  * regular printing characters. */
  926.     int numBytes, /* Number of bytes in string. */
  927.     int x, int y) /* Coordinates at which to place origin of the
  928.  * string when drawing. */
  929. {
  930.     MacDrawable *macWin = (MacDrawable *) drawable;
  931.     MacFont *fontPtr = (MacFont *) tkfont;
  932.     TkMacOSXDrawingContext drawingContext;
  933.     if (!TkMacOSXSetupDrawingContext(drawable, gc, 0, &drawingContext)) {
  934. return;
  935.     }
  936. #if 0
  937.     /*
  938.      * Stippled QD text drawing only kind of works and is ugly, so disable it
  939.      * for now:
  940.      */
  941.     if ((gc->fill_style == FillStippled
  942.     || gc->fill_style == FillOpaqueStippled)
  943.     && gc->stipple != None) {
  944. TkMacOSXDrawingContext pixmapDrawingContext;
  945. BitMapPtr stippleMap;
  946. Pixmap pixmap;
  947. Pattern white;
  948. Rect bounds = drawingContext.portBounds;
  949. OffsetRect(&bounds, macWin->xOff + x, 0);
  950. stippleMap = TkMacOSXMakeStippleMap(drawable, gc->stipple);
  951. pixmap = Tk_GetPixmap(display, drawable,
  952.     stippleMap->bounds.right, stippleMap->bounds.bottom, 0);
  953. if (!TkMacOSXSetupDrawingContext(pixmap, gc, 0,
  954. &pixmapDrawingContext)) {
  955.     return;
  956. }
  957. GetQDGlobalsWhite(&white);
  958. FillRect(&stippleMap->bounds, &white);
  959. MultiFontDrawText(fontPtr, source, numBytes, 0, macWin->yOff + y);
  960. TkMacOSXRestoreDrawingContext(&pixmapDrawingContext);
  961. CopyDeepMask(GetPortBitMapForCopyBits(TkMacOSXGetDrawablePort(pixmap)),
  962. stippleMap, GetPortBitMapForCopyBits(
  963. TkMacOSXGetDrawablePort(drawable)), &stippleMap->bounds,
  964. &stippleMap->bounds, &bounds, srcOr, NULL);
  965. /* TODO: this doesn't work quite right - it does a blend. You can't
  966.  * draw white text when you have a stipple.
  967.  */
  968. Tk_FreePixmap(display, pixmap);
  969. ckfree(stippleMap->baseAddr);
  970. ckfree((char *)stippleMap);
  971.     } else
  972. #endif
  973.     {
  974. MultiFontDrawText(fontPtr, source, numBytes, macWin->xOff + x,
  975. macWin->yOff + y);
  976.     }
  977.     TkMacOSXRestoreDrawingContext(&drawingContext);
  978. }
  979. /*
  980.  *-------------------------------------------------------------------------
  981.  *
  982.  * MultiFontDrawText --
  983.  *
  984.  * Helper function for Tk_DrawChars.  Draws characters, using the
  985.  * various screen fonts in fontPtr to draw multilingual characters.
  986.  * Note: No bidirectional support.
  987.  *
  988.  * Results:
  989.  * None.
  990.  *
  991.  * Side effects:
  992.  * Information gets drawn on the screen.
  993.  * Contents of fontPtr may be modified if more subfonts were loaded
  994.  * in order to draw all the multilingual characters in the given
  995.  * string.
  996.  *
  997.  *-------------------------------------------------------------------------
  998.  */
  999. static void
  1000. MultiFontDrawText(
  1001.     MacFont *fontPtr, /* Contains set of fonts to use when drawing
  1002.  * following string. */
  1003.     const char *source, /* Potentially multilingual UTF-8 string. */
  1004.     int numBytes, /* Length of string in bytes. */
  1005.     int x, int y) /* Coordinates at which to place origin *
  1006.  * of string when drawing. */
  1007. {
  1008.     SubFont *thisSubFontPtr, *lastSubFontPtr;
  1009.     FontFamily *familyPtr;
  1010.     Tcl_DString runString;
  1011.     const char *p, *end, *next;
  1012.     Tcl_UniChar ch;
  1013.     TextSize(fontPtr->size);
  1014.     TextFace(fontPtr->style);
  1015.     lastSubFontPtr = &fontPtr->subFontArray[0];
  1016.     end = source + numBytes;
  1017.     for (p = source; p < end; ) {
  1018. next = p + Tcl_UtfToUniChar(p, &ch);
  1019. thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
  1020. if (thisSubFontPtr != lastSubFontPtr) {
  1021.     if (p > source) {
  1022. familyPtr = lastSubFontPtr->familyPtr;
  1023. TextFont(familyPtr->faceNum);
  1024.  Tcl_UtfToExternalDString(familyPtr->encoding, source,
  1025. p - source, &runString);
  1026. MoveTo((short) x, (short) y);
  1027. DrawText(Tcl_DStringValue(&runString), 0,
  1028. Tcl_DStringLength(&runString));
  1029. x += TextWidth(Tcl_DStringValue(&runString), 0,
  1030. Tcl_DStringLength(&runString));
  1031. Tcl_DStringFree(&runString);
  1032. source = p;
  1033.     }
  1034.     lastSubFontPtr = thisSubFontPtr;
  1035. }
  1036. p = next;
  1037.     }
  1038.     if (p > source) {
  1039. familyPtr = lastSubFontPtr->familyPtr;
  1040. TextFont(familyPtr->faceNum);
  1041. Tcl_UtfToExternalDString(familyPtr->encoding, source,
  1042. p - source, &runString);
  1043. MoveTo((short) x, (short) y);
  1044.     DrawText(Tcl_DStringValue(&runString), 0,
  1045. Tcl_DStringLength(&runString));
  1046. Tcl_DStringFree(&runString);
  1047.     }
  1048. }
  1049. /*
  1050.  *---------------------------------------------------------------------------
  1051.  *
  1052.  * TkMacOSXIsCharacterMissing --
  1053.  *
  1054.  * Given a tkFont and a character determines whether the character has
  1055.  * a glyph defined in the font or not. Note that this is potentially
  1056.  * not compatible with Mac OS 8 as it looks at the font handle
  1057.  * structure directly. Looks into the character array of the font
  1058.  * handle to determine whether the glyph is defined or not.
  1059.  *
  1060.  * Results:
  1061.  * Returns a 1 if the character is missing, a 0 if it is not.
  1062.  *
  1063.  * Side effects:
  1064.  * None.
  1065.  *
  1066.  *---------------------------------------------------------------------------
  1067.  */
  1068. int
  1069. TkMacOSXIsCharacterMissing(
  1070.     Tk_Font tkfont, /* The font we are looking in. */
  1071.     unsigned int searchChar) /* The character we are looking for. */
  1072. {
  1073.     /*
  1074.      * For some reason, FMSwapFont always returns a NULL font handle under OS X
  1075.      * Until we figure this one out, return 0;
  1076.      */
  1077.     return 0;
  1078. }
  1079. /*
  1080.  *---------------------------------------------------------------------------
  1081.  *
  1082.  * InitFont --
  1083.  *
  1084.  * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().
  1085.  * Initializes the memory for a MacFont that wraps the platform-specific
  1086.  * data.
  1087.  *
  1088.  * The caller is responsible for initializing the fields of the
  1089.  * TkFont that are used exclusively by the generic TkFont code, and
  1090.  * for releasing those fields before calling TkpDeleteFont().
  1091.  *
  1092.  * Results:
  1093.  * Fills the MacFont structure.
  1094.  *
  1095.  * Side effects:
  1096.  * Memory allocated.
  1097.  *
  1098.  *---------------------------------------------------------------------------
  1099.  */
  1100. static void
  1101. InitFont(
  1102.     Tk_Window tkwin, /* For display where font will be used. */
  1103.     int faceNum, /* Macintosh font number. */
  1104.     unsigned char *familyName, /* The font family name or NULL. */
  1105.     int size, /* Point size for Macintosh font. */
  1106.     int style, /* Macintosh style bits. */
  1107.     MacFont *fontPtr) /* Filled with information constructed from
  1108.  * the above arguments. */
  1109. {
  1110.     Str255 nativeName;
  1111.     FontInfo fi;
  1112.     TkFontAttributes *faPtr;
  1113.     TkFontMetrics *fmPtr;
  1114.     CGrafPtr savePort;
  1115.     Boolean portChanged;
  1116.     short pixels;
  1117.     if (size == 0) {
  1118.     size = -GetDefFontSize();
  1119.     }
  1120.     pixels = (short) TkFontGetPixels(tkwin, size);
  1121.     portChanged = QDSwapPort(gWorld, &savePort);
  1122.     TextFont(faceNum);
  1123.     TextSize(pixels);
  1124.     TextFace(style);
  1125.     GetFontInfo(&fi);
  1126.     if (!familyName) {
  1127. GetFontName(faceNum, nativeName);
  1128. familyName = nativeName;
  1129.     }
  1130.     fontPtr->font.fid      = (Font) fontPtr;
  1131.     faPtr = &fontPtr->font.fa;
  1132.     faPtr->family = GetUtfFaceName(familyName);
  1133.     faPtr->size = TkFontGetPoints(tkwin, size);
  1134.     faPtr->weight = (style & bold) ? TK_FW_BOLD : TK_FW_NORMAL;
  1135.     faPtr->slant = (style & italic) ? TK_FS_ITALIC : TK_FS_ROMAN;
  1136.     faPtr->underline = ((style & underline) != 0);
  1137.     faPtr->overstrike = 0;
  1138.     fmPtr = &fontPtr->font.fm;
  1139.     fmPtr->ascent = fi.ascent;
  1140.     fmPtr->descent = fi.descent;
  1141.     fmPtr->maxWidth = fi.widMax;
  1142.     fmPtr->fixed = (CharWidth('i') == CharWidth('w'));
  1143.     fontPtr->size = pixels;
  1144.     fontPtr->style = (short) style;
  1145.     fontPtr->numSubFonts = 1;
  1146.     fontPtr->subFontArray = fontPtr->staticSubFonts;
  1147.     InitSubFont(fontPtr, faceNum, &fontPtr->subFontArray[0]);
  1148.     if (portChanged) {
  1149. QDSwapPort(savePort, NULL);
  1150.     }
  1151. }
  1152. /*
  1153.  *-------------------------------------------------------------------------
  1154.  *
  1155.  * ReleaseFont --
  1156.  *
  1157.  * Called to release the Macintosh-specific contents of a TkFont.
  1158.  * The caller is responsible for freeing the memory used by the
  1159.  * font itself.
  1160.  *
  1161.  * Results:
  1162.  * None.
  1163.  *
  1164.  * Side effects:
  1165.  * Memory is freed.
  1166.  *
  1167.  *---------------------------------------------------------------------------
  1168.  */
  1169. static void
  1170. ReleaseFont(
  1171.     MacFont *fontPtr) /* The font to delete. */
  1172. {
  1173.     int i;
  1174.     for (i = 0; i < fontPtr->numSubFonts; i++) {
  1175. ReleaseSubFont(&fontPtr->subFontArray[i]);
  1176.     }
  1177.     if (fontPtr->subFontArray != fontPtr->staticSubFonts) {
  1178. ckfree((char *) fontPtr->subFontArray);
  1179.     }
  1180. }
  1181. /*
  1182.  *-------------------------------------------------------------------------
  1183.  *
  1184.  * InitSubFont --
  1185.  *
  1186.  * Wrap a screen font and load the FontFamily that represents
  1187.  * it.  Used to prepare a SubFont so that characters can be mapped
  1188.  * from UTF-8 to the charset of the font.
  1189.  *
  1190.  * Results:
  1191.  * The subFontPtr is filled with information about the font.
  1192.  *
  1193.  * Side effects:
  1194.  * None.
  1195.  *
  1196.  *-------------------------------------------------------------------------
  1197.  */
  1198. static void
  1199. InitSubFont(
  1200.     const MacFont *fontPtr, /* Font object in which the SubFont will be
  1201.  * used. */
  1202.     int faceNum, /* The font number. */
  1203.     SubFont *subFontPtr) /* Filled with SubFont constructed from
  1204.  * above attributes. */
  1205. {
  1206.     subFontPtr->familyPtr = AllocFontFamily(fontPtr, faceNum);
  1207.     subFontPtr->fontMap = subFontPtr->familyPtr->fontMap;
  1208. }
  1209. /*
  1210.  *-------------------------------------------------------------------------
  1211.  *
  1212.  * ReleaseSubFont --
  1213.  *
  1214.  * Called to release the contents of a SubFont. The caller is
  1215.  * responsible for freeing the memory used by the SubFont itself.
  1216.  *
  1217.  * Results:
  1218.  * None.
  1219.  *
  1220.  * Side effects:
  1221.  * Memory and resources are freed.
  1222.  *
  1223.  *---------------------------------------------------------------------------
  1224.  */
  1225. static void
  1226. ReleaseSubFont(
  1227.     SubFont *subFontPtr) /* The SubFont to delete. */
  1228. {
  1229.     FreeFontFamily(subFontPtr->familyPtr);
  1230. }
  1231. /*
  1232.  *-------------------------------------------------------------------------
  1233.  *
  1234.  * AllocFontFamily --
  1235.  *
  1236.  * Find the FontFamily structure associated with the given font
  1237.  * family.  The information should be stored by the caller in a
  1238.  * SubFont and used when determining if that SubFont supports a
  1239.  * character.
  1240.  *
  1241.  * Results:
  1242.  * A pointer to a FontFamily.  The reference count in the FontFamily
  1243.  * is automatically incremented. When the SubFont is released, the
  1244.  * reference count is decremented.  When no SubFont is using this
  1245.  * FontFamily, it may be deleted.
  1246.  *
  1247.  * Side effects:
  1248.  * A new FontFamily structure will be allocated if this font family
  1249.  * has not been seen.
  1250.  *
  1251.  *-------------------------------------------------------------------------
  1252.  */
  1253. static FontFamily *
  1254. AllocFontFamily(
  1255.     const MacFont *fontPtr, /* Font object in which the FontFamily will
  1256.  * be used. */
  1257.     int faceNum) /* The font number. */
  1258. {
  1259.     FontFamily *familyPtr;
  1260.     int i;
  1261.     familyPtr = fontFamilyList;
  1262.     for (; familyPtr != NULL; familyPtr = familyPtr->nextPtr) {
  1263. if (familyPtr->faceNum == faceNum) {
  1264.     familyPtr->refCount++;
  1265.     return familyPtr;
  1266. }
  1267.     }
  1268.     familyPtr = (FontFamily *) ckalloc(sizeof(FontFamily));
  1269.     memset(familyPtr, 0, sizeof(FontFamily));
  1270.     familyPtr->nextPtr = fontFamilyList;
  1271.     fontFamilyList = familyPtr;
  1272.     /*
  1273.      * Set key for this FontFamily.
  1274.      */
  1275.     familyPtr->faceNum = faceNum;
  1276.     /*
  1277.      * An initial refCount of 2 means that FontFamily information will
  1278.      * persist even when the SubFont that loaded the FontFamily is released.
  1279.      * Change it to 1 to cause FontFamilies to be unloaded when not in use.
  1280.      */
  1281.     familyPtr->refCount = 2;
  1282.     familyPtr->encoding = GetFontEncoding(faceNum, 1, &familyPtr->isSymbolFont);
  1283.     familyPtr->isMultiByteFont = 0;
  1284.     FillParseTable(familyPtr->typeTable, FontToScript(faceNum));
  1285.     for (i = 0; i < 256; i++) {
  1286. if (familyPtr->typeTable[i] != 0) {
  1287.     familyPtr->isMultiByteFont = 1;
  1288.     break;
  1289. }
  1290.     }
  1291.     return familyPtr;
  1292. }
  1293. /*
  1294.  *-------------------------------------------------------------------------
  1295.  *
  1296.  * FreeFontFamily --
  1297.  *
  1298.  * Called to free a FontFamily when the SubFont is finished using it.
  1299.  * Frees the contents of the FontFamily and the memory used by the
  1300.  * FontFamily itself.
  1301.  *
  1302.  * Results:
  1303.  * None.
  1304.  *
  1305.  * Side effects:
  1306.  * None.
  1307.  *
  1308.  *-------------------------------------------------------------------------
  1309.  */
  1310. static void
  1311. FreeFontFamily(
  1312.     FontFamily *familyPtr) /* The FontFamily to delete. */
  1313. {
  1314.     FontFamily **familyPtrPtr;
  1315.     int i;
  1316.     if (familyPtr == NULL) {
  1317. return;
  1318.     }
  1319.     familyPtr->refCount--;
  1320.     if (familyPtr->refCount > 0) {
  1321.     return;
  1322.     }
  1323.     Tcl_FreeEncoding(familyPtr->encoding);
  1324.     for (i = 0; i < FONTMAP_PAGES; i++) {
  1325. if (familyPtr->fontMap[i] != NULL) {
  1326.     ckfree((char *) familyPtr->fontMap[i]);
  1327. }
  1328.     }
  1329.     /*
  1330.      * Delete from list.
  1331.      */
  1332.     for (familyPtrPtr = &fontFamilyList; ; ) {
  1333. if (*familyPtrPtr == familyPtr) {
  1334.       *familyPtrPtr = familyPtr->nextPtr;
  1335.     break;
  1336. }
  1337. familyPtrPtr = &(*familyPtrPtr)->nextPtr;
  1338.     }
  1339.     ckfree((char *) familyPtr);
  1340. }
  1341. /*
  1342.  *-------------------------------------------------------------------------
  1343.  *
  1344.  * FindSubFontForChar --
  1345.  *
  1346.  * Determine which physical screen font is necessary to use to
  1347.  * display the given character. If the font object does not have
  1348.  * a screen font that can display the character, another screen font
  1349.  * may be loaded into the font object, following a set of preferred
  1350.  * fallback rules.
  1351.  *
  1352.  * Results:
  1353.  * The return value is the SubFont to use to display the given
  1354.  * character.
  1355.  *
  1356.  * Side effects:
  1357.  * The contents of fontPtr are modified to cache the results
  1358.  * of the lookup and remember any SubFonts that were dynamically
  1359.  * loaded.  The table of SubFonts might be extended, and if a non-NULL
  1360.  * reference to a subfont pointer is available, it is updated if it
  1361.  * previously pointed into the old subfont table.
  1362.  *
  1363.  *-------------------------------------------------------------------------
  1364.  */
  1365. static SubFont *
  1366. FindSubFontForChar(
  1367.     MacFont *fontPtr, /* The font object with which the character
  1368.  * will be displayed. */
  1369.     int ch, /* The Unicode character to be displayed. */
  1370.     SubFont **fixSubFontPtrPtr) /* Subfont reference to fix up if we
  1371.  * reallocate our subfont table. */
  1372. {
  1373.     int i, j, k;
  1374.     const char *fallbackName;
  1375.     char **aliases;
  1376.     SubFont *subFontPtr;
  1377.     FontNameMap *mapPtr;
  1378.     Tcl_DString faceNames;
  1379.     char ***fontFallbacks;
  1380.     char **anyFallbacks;
  1381.     if (FontMapLookup(&fontPtr->subFontArray[0], ch)) {
  1382. return &fontPtr->subFontArray[0];
  1383.     }
  1384.     for (i = 1; i < fontPtr->numSubFonts; i++) {
  1385. if (FontMapLookup(&fontPtr->subFontArray[i], ch)) {
  1386.     return &fontPtr->subFontArray[i];
  1387. }
  1388.     }
  1389.     /*
  1390.      * Keep track of all face names that we check, so we don't check some
  1391.      * name multiple times if it can be reached by multiple paths.
  1392.      */
  1393.     Tcl_DStringInit(&faceNames);
  1394.     aliases = TkFontGetAliasList(fontPtr->font.fa.family);
  1395.     subFontPtr = NULL;
  1396.     fontFallbacks = TkFontGetFallbacks();
  1397.     for (i = 0; fontFallbacks[i] != NULL; i++) {
  1398. for (j = 0; fontFallbacks[i][j] != NULL; j++) {
  1399.     fallbackName = fontFallbacks[i][j];
  1400.     if (strcasecmp(fallbackName, fontPtr->font.fa.family) == 0) {
  1401. /*
  1402.  * If the base font has a fallback...
  1403.  */
  1404. goto tryfallbacks;
  1405.     } else if (aliases != NULL) {
  1406. /*
  1407.  * Or if an alias for the base font has a fallback...
  1408.  */
  1409. for (k = 0; aliases[k] != NULL; k++) {
  1410.     if (strcasecmp(aliases[k], fallbackName) == 0) {
  1411. goto tryfallbacks;
  1412.     }
  1413. }
  1414.     }
  1415. }
  1416. continue;
  1417. /*
  1418.  * ...then see if we can use one of the fallbacks, or an
  1419.  * alias for one of the fallbacks.
  1420.  */
  1421. tryfallbacks:
  1422. for (j = 0; fontFallbacks[i][j] != NULL; j++) {
  1423.     fallbackName = fontFallbacks[i][j];
  1424.     subFontPtr = CanUseFallbackWithAliases(fontPtr, fallbackName,
  1425.     ch, &faceNames, fixSubFontPtrPtr);
  1426.     if (subFontPtr != NULL) {
  1427. goto end;
  1428.     }
  1429. }
  1430.     }
  1431.     /*
  1432.      * See if we can use something from the global fallback list.
  1433.      */
  1434.     anyFallbacks = TkFontGetGlobalClass();
  1435.     for (i = 0; anyFallbacks[i] != NULL; i++) {
  1436. fallbackName = anyFallbacks[i];
  1437. subFontPtr = CanUseFallbackWithAliases(fontPtr, fallbackName, ch,
  1438. &faceNames, fixSubFontPtrPtr);
  1439. if (subFontPtr != NULL) {
  1440.     goto end;
  1441. }
  1442.     }
  1443.     /*
  1444.      * Try all face names available in the whole system until we
  1445.      * find one that can be used.
  1446.      */
  1447.     for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) {
  1448. fallbackName = mapPtr->utfName;
  1449. if (SeenName(fallbackName, &faceNames) == 0) {
  1450.     subFontPtr = CanUseFallback(fontPtr, fallbackName, ch,
  1451.     fixSubFontPtrPtr);
  1452.     if (subFontPtr != NULL) {
  1453. goto end;
  1454.     }
  1455. }
  1456.     }
  1457.     end:
  1458.     Tcl_DStringFree(&faceNames);
  1459.     if (subFontPtr == NULL) {
  1460. /*
  1461.  * No font can display this character. We will use the base font
  1462.  * and have it display the "unknown" character.
  1463.  */
  1464. subFontPtr = &fontPtr->subFontArray[0];
  1465. FontMapInsert(subFontPtr, ch);
  1466.     }
  1467.     return subFontPtr;
  1468. }
  1469. /*
  1470.  *-------------------------------------------------------------------------
  1471.  *
  1472.  * FontMapLookup --
  1473.  *
  1474.  * See if the screen font can display the given character.
  1475.  *
  1476.  * Results:
  1477.  * The return value is 0 if the screen font cannot display the
  1478.  * character, non-zero otherwise.
  1479.  *
  1480.  * Side effects:
  1481.  * New pages are added to the font mapping cache whenever the
  1482.  * character belongs to a page that hasn't been seen before.
  1483.  * When a page is loaded, information about all the characters on
  1484.  * that page is stored, not just for the single character in
  1485.  * question.
  1486.  *
  1487.  *-------------------------------------------------------------------------
  1488.  */
  1489. static int
  1490. FontMapLookup(
  1491.     SubFont *subFontPtr, /* Contains font mapping cache to be queried
  1492.  * and possibly updated. */
  1493.     int ch) /* Character to be tested. */
  1494. {
  1495.     int row, bitOffset;
  1496.     row = ch >> FONTMAP_SHIFT;
  1497.     if (subFontPtr->fontMap[row] == NULL) {
  1498. FontMapLoadPage(subFontPtr, row);
  1499.     }
  1500.     bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);
  1501.     return (subFontPtr->fontMap[row][bitOffset >> 3] >> (bitOffset & 7)) & 1;
  1502. }
  1503. /*
  1504.  *-------------------------------------------------------------------------
  1505.  *
  1506.  * FontMapInsert --
  1507.  *
  1508.  * Tell the font mapping cache that the given screen font should be
  1509.  * used to display the specified character.  This is called when no
  1510.  * font on the system can be be found that can display that
  1511.  * character; we lie to the font and tell it that it can display
  1512.  * the character, otherwise we would end up re-searching the entire
  1513.  * fallback hierarchy every time that character was seen.
  1514.  *
  1515.  * Results:
  1516.  * None.
  1517.  *
  1518.  * Side effects:
  1519.  * New pages are added to the font mapping cache whenever the
  1520.  * character belongs to a page that hasn't been seen before.
  1521.  * When a page is loaded, information about all the characters on
  1522.  * that page is stored, not just for the single character in
  1523.  * question.
  1524.  *
  1525.  *-------------------------------------------------------------------------
  1526.  */
  1527. static void
  1528. FontMapInsert(
  1529.     SubFont *subFontPtr, /* Contains font mapping cache to be
  1530.  * updated. */
  1531.     int ch) /* Character to be added to cache. */
  1532. {
  1533.     int row, bitOffset;
  1534.     row = ch >> FONTMAP_SHIFT;
  1535.     if (subFontPtr->fontMap[row] == NULL) {
  1536. FontMapLoadPage(subFontPtr, row);
  1537.     }
  1538.     bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);
  1539.     subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);
  1540. }
  1541. /*
  1542.  *-------------------------------------------------------------------------
  1543.  *
  1544.  * FontMapLoadPage --
  1545.  *
  1546.  * Load information about all the characters on a given page.
  1547.  * This information consists of one bit per character that indicates
  1548.  * whether the associated HFONT can (1) or cannot (0) display the
  1549.  * characters on the page.
  1550.  *
  1551.  * Results:
  1552.  * None.
  1553.  *
  1554.  * Side effects:
  1555.  * Mempry allocated.
  1556.  *
  1557.  *-------------------------------------------------------------------------
  1558.  */
  1559. static void
  1560. FontMapLoadPage(
  1561.     SubFont *subFontPtr, /* Contains font mapping cache to be
  1562.  * updated. */
  1563.     int row) /* Index of the page to be loaded into
  1564.  * the cache. */
  1565. {
  1566.     FMInput  fm;
  1567.     FMOutPtr fmOut;
  1568.     int i, end, bitOffset, isMultiByteFont;
  1569.     char src[TCL_UTF_MAX];
  1570.     unsigned char buf[16];
  1571.     int srcRead, dstWrote;
  1572.     Tcl_Encoding encoding;
  1573.     Handle fHandle = NULL;
  1574.     subFontPtr->fontMap[row] = (char *) ckalloc(FONTMAP_BITSPERPAGE / 8);
  1575.     memset(subFontPtr->fontMap[row], 0, FONTMAP_BITSPERPAGE / 8);
  1576.     encoding = subFontPtr->familyPtr->encoding;
  1577.     fm.family = subFontPtr->familyPtr->faceNum;
  1578.     fm.size = 12;
  1579.     fm.face = 0;
  1580.     fm.needBits = 0;
  1581.     fm.device = 0;
  1582.     fm.numer.h = 1;
  1583.     fm.numer.v = 1;
  1584.     fm.denom.h = 1;
  1585.     fm.denom.v = 1;
  1586. /*
  1587.  * For some reason, FMSwapFont alywas returns a structure where the returned font handle
  1588.  * is NULL. Until we figure this one out, assume all characters are allowed
  1589.  */
  1590.     fmOut = FMSwapFont(&fm);
  1591.     fHandle = fmOut->fontHandle;
  1592.     isMultiByteFont = subFontPtr->familyPtr->isMultiByteFont;
  1593. /*
  1594.  * Found an outline font which has very complex font record.
  1595.  * Let's just assume *ALL* the characters are allowed.
  1596.  */
  1597. end = (row + 1) << FONTMAP_SHIFT;
  1598. for (i = row << FONTMAP_SHIFT; i < end; i++) {
  1599.     if (Tcl_UtfToExternal(NULL, encoding, src, Tcl_UniCharToUtf(i,
  1600.     src),
  1601.     TCL_ENCODING_STOPONERROR, NULL, (char *) buf,
  1602.     sizeof(buf),
  1603.     &srcRead, &dstWrote, NULL) == TCL_OK) {
  1604. bitOffset = i & (FONTMAP_BITSPERPAGE - 1);
  1605. subFontPtr->fontMap[row][bitOffset >> 3] |= 1
  1606.    << (bitOffset & 7);
  1607.     }
  1608. }
  1609. }
  1610. /*
  1611.  *---------------------------------------------------------------------------
  1612.  *
  1613.  * CanUseFallbackWithAliases --
  1614.  *
  1615.  * Helper function for FindSubFontForChar.  Determine if the
  1616.  * specified face name (or an alias of the specified face name)
  1617.  * can be used to construct a screen font that can display the
  1618.  * given character.
  1619.  *
  1620.  * Results:
  1621.  * See CanUseFallback().
  1622.  *
  1623.  * Side effects:
  1624.  * If the name and/or one of its aliases was rejected, the
  1625.  * rejected string is recorded in nameTriedPtr so that it won't
  1626.  * be tried again.  The table of SubFonts might be extended, and if
  1627.  * a non-NULL reference to a subfont pointer is available, it is
  1628.  * updated if it previously pointed into the old subfont table.
  1629.  *
  1630.  *---------------------------------------------------------------------------
  1631.  */
  1632. static SubFont *
  1633. CanUseFallbackWithAliases(
  1634.     MacFont *fontPtr, /* The font object that will own the new
  1635.  * screen font. */
  1636.     const char *faceName, /* Desired face name for new screen font. */
  1637.     int ch, /* The Unicode character that the new
  1638.  * screen font must be able to display. */
  1639.     Tcl_DString *nameTriedPtr, /* Records face names that have already
  1640.  * been tried. It is possible for the same
  1641.  * face name to be queried multiple times when
  1642.  * trying to find a suitable screen font. */
  1643.     SubFont **fixSubFontPtrPtr) /* Subfont reference to fix up if we
  1644.  * reallocate our subfont table. */
  1645. {
  1646.     SubFont *subFontPtr;
  1647.     char **aliases;
  1648.     int i;
  1649.     if (SeenName(faceName, nameTriedPtr) == 0) {
  1650. subFontPtr = CanUseFallback(fontPtr, faceName, ch, fixSubFontPtrPtr);
  1651. if (subFontPtr != NULL) {
  1652.     return subFontPtr;
  1653. }
  1654.     }
  1655.     aliases = TkFontGetAliasList(faceName);
  1656.     if (aliases != NULL) {
  1657. for (i = 0; aliases[i] != NULL; i++) {
  1658.     if (SeenName(aliases[i], nameTriedPtr) == 0) {
  1659. subFontPtr = CanUseFallback(fontPtr, aliases[i], ch,
  1660. fixSubFontPtrPtr);
  1661. if (subFontPtr != NULL) {
  1662.     return subFontPtr;
  1663. }
  1664.     }
  1665. }
  1666.     }
  1667.     return NULL;
  1668. }
  1669. /*
  1670.  *---------------------------------------------------------------------------
  1671.  *
  1672.  * SeenName --
  1673.  *
  1674.  * Used to determine we have already tried and rejected the given
  1675.  * face name when looking for a screen font that can support some
  1676.  * Unicode character.
  1677.  *
  1678.  * Results:
  1679.  * The return value is 0 if this face name has not already been seen,
  1680.  * non-zero otherwise.
  1681.  *
  1682.  * Side effects:
  1683.  * None.
  1684.  *
  1685.  *---------------------------------------------------------------------------
  1686.  */
  1687. static int
  1688. SeenName(
  1689.     const char *name, /* The name to check. */
  1690.     Tcl_DString *dsPtr) /* Contains names that have already been
  1691.  * seen. */
  1692. {
  1693.     const char *seen, *end;
  1694.     seen = Tcl_DStringValue(dsPtr);
  1695.     end = seen + Tcl_DStringLength(dsPtr);
  1696.     while (seen < end) {
  1697. if (strcasecmp(seen, name) == 0) {
  1698.     return 1;
  1699. }
  1700. seen += strlen(seen) + 1;
  1701.     }
  1702.     Tcl_DStringAppend(dsPtr, (char *) name, (int) (strlen(name) + 1));
  1703.     return 0;
  1704. }
  1705. /*
  1706.  *-------------------------------------------------------------------------
  1707.  *
  1708.  * CanUseFallback --
  1709.  *
  1710.  * If the specified physical screen font has not already been loaded
  1711.  * into the font object, determine if the specified physical screen
  1712.  * font can display the given character.
  1713.  *
  1714.  * Results:
  1715.  * The return value is a pointer to a newly allocated SubFont, owned
  1716.  * by the font object.  This SubFont can be used to display the given
  1717.  * character.  The SubFont represents the screen font with the base set
  1718.  * of font attributes from the font object, but using the specified
  1719.  * font name.  NULL is returned if the font object already holds
  1720.  * a reference to the specified physical font or if the specified
  1721.  * physical font cannot display the given character.
  1722.  *
  1723.  * Side effects:
  1724.  * The font object's subFontArray is updated to contain a reference
  1725.  * to the newly allocated SubFont.  The table of SubFonts might be
  1726.  * extended, and if a non-NULL reference to a subfont pointer is
  1727.  * available, it is updated if it previously pointed into the old
  1728.  * subfont table.
  1729.  *
  1730.  *-------------------------------------------------------------------------
  1731.  */
  1732. static SubFont *
  1733. CanUseFallback(
  1734.     MacFont *fontPtr, /* The font object that will own the new
  1735.  * screen font. */
  1736.     const char *faceName, /* Desired face name for new screen font. */
  1737.     int ch, /* The Unicode character that the new
  1738.  * screen font must be able to display. */
  1739.     SubFont **fixSubFontPtrPtr) /* Subfont reference to fix up if we
  1740.  * reallocate our subfont table. */
  1741. {
  1742.     int i;
  1743.     SubFont subFont;
  1744.     short faceNum;
  1745.     if (GetFamilyNum(faceName, &faceNum) == 0) {
  1746. return NULL;
  1747.     }
  1748.     /*
  1749.      * Skip all fonts we've already used.
  1750.      */
  1751.     for (i = 0; i < fontPtr->numSubFonts; i++) {
  1752. if (faceNum == fontPtr->subFontArray[i].familyPtr->faceNum) {
  1753.     return NULL;
  1754. }
  1755.     }
  1756.     /*
  1757.      * Load this font and see if it has the desired character.
  1758.      */
  1759.     InitSubFont(fontPtr, faceNum, &subFont);
  1760.     if (((ch < 256) && (subFont.familyPtr->isSymbolFont))
  1761.     || (FontMapLookup(&subFont, ch) == 0)) {
  1762. ReleaseSubFont(&subFont);
  1763. return NULL;
  1764.     }
  1765.     if (fontPtr->numSubFonts >= SUBFONT_SPACE) {
  1766. SubFont *newPtr = (SubFont *) ckalloc(sizeof(SubFont)
  1767. * (fontPtr->numSubFonts + 1));
  1768. memcpy((char *) newPtr, fontPtr->subFontArray,
  1769. fontPtr->numSubFonts * sizeof(SubFont));
  1770. if (fixSubFontPtrPtr != NULL) {
  1771.     /*
  1772.      * Fix up the variable pointed to by fixSubFontPtrPtr so it
  1773.      * still points into the live array.  [Bug 618872]
  1774.      */
  1775.     *fixSubFontPtrPtr =
  1776.     newPtr + (*fixSubFontPtrPtr - fontPtr->subFontArray);
  1777. }
  1778. if (fontPtr->subFontArray != fontPtr->staticSubFonts) {
  1779.     ckfree((char *) fontPtr->subFontArray);
  1780. }
  1781. fontPtr->subFontArray = newPtr;
  1782.     }
  1783.     fontPtr->subFontArray[fontPtr->numSubFonts] = subFont;
  1784.     fontPtr->numSubFonts++;
  1785.     return &fontPtr->subFontArray[fontPtr->numSubFonts - 1];
  1786. }
  1787. /*
  1788.  *-------------------------------------------------------------------------
  1789.  *
  1790.  * GetFamilyNum --
  1791.  *
  1792.  * Determines if any physical screen font exists on the system with
  1793.  * the given family name.  If the family exists, then it should be
  1794.  * possible to construct some physical screen font with that family
  1795.  * name.
  1796.  *
  1797.  * Results:
  1798.  * The return value is 0 if the specified font family does not exist,
  1799.  * non-zero otherwise.  *faceNumPtr is filled with the unique face
  1800.  * number that identifies the screen font, or 0 if the font family
  1801.  * did not exist.
  1802.  *
  1803.  * Side effects:
  1804.  * None.
  1805.  *
  1806.  *-------------------------------------------------------------------------
  1807.  */
  1808. static int
  1809. GetFamilyNum(
  1810.     const char *faceName,   /* UTF-8 name of font family to query. */
  1811.     short *faceNumPtr)   /* Filled with font number for above family. */
  1812. {
  1813.     FontNameMap *mapPtr;
  1814.     if (faceName != NULL) {
  1815. for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) {
  1816.     if (strcasecmp(faceName, mapPtr->utfName) == 0) {
  1817. *faceNumPtr = mapPtr->faceNum;
  1818. return 1;
  1819.     }
  1820. }
  1821.     }
  1822.     *faceNumPtr = 0;
  1823.     return 0;
  1824. }
  1825. static int
  1826. GetFamilyOrAliasNum(
  1827.     const char *faceName,   /* UTF-8 name of font family to query. */
  1828.     short *faceNumPtr)   /* Filled with font number for above family. */
  1829. {
  1830.     char **aliases;
  1831.     int i;
  1832.     if (GetFamilyNum(faceName, faceNumPtr) != 0) {
  1833. return 1;
  1834.     }
  1835.     aliases = TkFontGetAliasList(faceName);
  1836.     if (aliases != NULL) {
  1837. for (i = 0; aliases[i] != NULL; i++) {
  1838.     if (GetFamilyNum(aliases[i], faceNumPtr) != 0) {
  1839. return 1;
  1840.     }
  1841. }
  1842.     }
  1843.     return 0;
  1844. }
  1845. /*
  1846.  *-------------------------------------------------------------------------
  1847.  *
  1848.  * GetUtfFaceName --
  1849.  *
  1850.  * Given the native name for a Macintosh font (in which the name of
  1851.  * the font is in the encoding of the font itself), return the UTF-8
  1852.  * name that corresponds to that font.  The specified font name must
  1853.  * refer to a font that actually exists on the machine.
  1854.  *
  1855.  * This function is used to obtain the UTF-8 name when querying the
  1856.  * properties of a Macintosh font object.
  1857.  *
  1858.  * Results:
  1859.  * The return value is a pointer to the UTF-8 of the specified font.
  1860.  *
  1861.  * Side effects:
  1862.  * None.
  1863.  *
  1864.  *------------------------------------------------------------------------
  1865.  */
  1866. static Tk_Uid
  1867. GetUtfFaceName(
  1868.     StringPtr nativeName)  /* Pascal name for font in native encoding. */
  1869. {
  1870.     FontNameMap *mapPtr;
  1871.     for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) {
  1872. if (pstrcmp(nativeName, mapPtr->nativeName) == 0) {
  1873.     return mapPtr->utfName;
  1874. }
  1875.     }
  1876.     Tcl_Panic("GetUtfFaceName: unexpected nativeName");
  1877.     return NULL;
  1878. }
  1879. /*
  1880.  *------------------------------------------------------------------------
  1881.  *
  1882.  * GetFontEncoding --
  1883.  *
  1884.  * Return a string that can be passed to Tcl_GetTextEncoding() and
  1885.  * used to convert bytes from UTF-8 into the encoding  of the
  1886.  * specified font.
  1887.  *
  1888.  * The desired encoding to use to convert the name of a symbolic
  1889.  * font into UTF-8 is macRoman, while the desired encoding to use
  1890.  * to convert bytes in a symbolic font to UTF-8 is the corresponding
  1891.  * symbolic encoding.  Due to this dual interpretatation of symbolic
  1892.  * fonts, the caller can specify what type of encoding to return
  1893.  * should the specified font be symbolic.
  1894.  *
  1895.  * Results:
  1896.  * The return value is a string that specifies the font's encoding.
  1897.  * If the font's encoding could not be identified, NULL is returned.
  1898.  *
  1899.  * Side effects:
  1900.  * None.
  1901.  *
  1902.  *------------------------------------------------------------------------
  1903.  */
  1904. static Tcl_Encoding
  1905. GetFontEncoding(
  1906.     int faceNum, /* Macintosh font number. */
  1907.     int allowSymbol, /* If non-zero, then the encoding string
  1908.  * for symbol fonts will be the corresponding
  1909.  * symbol encoding.  Otherwise, the encoding
  1910.  * string for symbol fonts will be
  1911.  * "macRoman". */
  1912.     int *isSymbolPtr) /* Filled with non-zero if this font is a
  1913.  * symbol font, 0 otherwise. */
  1914. {
  1915.     Str255 faceName;
  1916.     int script, lang;
  1917.     char *name;
  1918.     if (allowSymbol != 0) {
  1919. GetFontName(faceNum, faceName);
  1920. if (pstrcasecmp(faceName, "psymbol") == 0) {
  1921.     *isSymbolPtr = 1;
  1922. return Tcl_GetEncoding(NULL, "symbol");
  1923. }
  1924. if (pstrcasecmp(faceName, "pzapf dingbats") == 0) {
  1925.     *isSymbolPtr = 1;
  1926.     return Tcl_GetEncoding(NULL, "macDingbats");
  1927. }
  1928.     }
  1929.     *isSymbolPtr = 0;
  1930.     script = FontToScript(faceNum);
  1931.     lang = GetScriptVariable(script, smScriptLang);
  1932.     name = NULL;
  1933.     if (script == smRoman) {
  1934. name = TkFindStateString(romanMap, lang);
  1935.     } else if (script == smCyrillic) {
  1936. name = TkFindStateString(cyrillicMap, lang);
  1937.     }
  1938.     if (name == NULL) {
  1939. name = TkFindStateString(scriptMap, script);
  1940.     }
  1941.     return Tcl_GetEncoding(NULL, name);
  1942. }
  1943. /*
  1944.  *----------------------------------------------------------------------
  1945.  *
  1946.  * TkMacOSXInitControlFontStyle --
  1947.  *
  1948.  * This procedure sets up the appropriate ControlFontStyleRec
  1949.  * for a Mac control.
  1950.  *
  1951.  * Results:
  1952.  * None.
  1953.  *
  1954.  * Side effects:
  1955.  * None.
  1956.  *
  1957.  *----------------------------------------------------------------------
  1958.  */
  1959. void
  1960. TkMacOSXInitControlFontStyle(
  1961.     Tk_Font tkfont,
  1962.     ControlFontStylePtr fsPtr)
  1963. {
  1964.     MacFont    *fontPtr = (MacFont *) tkfont;
  1965.     FontFamily *lastFamilyPtr = fontPtr->subFontArray[0].familyPtr;
  1966.     fsPtr->flags = kControlUseFontMask | kControlUseSizeMask |
  1967.     kControlUseFaceMask | kControlUseJustMask;
  1968.     fsPtr->font = lastFamilyPtr->faceNum;
  1969.     fsPtr->size = fontPtr->size;
  1970.     fsPtr->style = fontPtr->style;
  1971.     fsPtr->just = teCenter;
  1972. }
  1973. /*
  1974.  *----------------------------------------------------------------------
  1975.  *
  1976.  * TkMacOSXUseAntialiasedText --
  1977.  *
  1978.  * Enables or disables application-wide use of quickdraw
  1979.  * antialiased text (where available).
  1980.  * Sets up a linked tcl global boolean variable with write trace
  1981.  * to allow disabling of antialiased text from tcl.
  1982.  *
  1983.  * Results:
  1984.  * TCL_OK if facility was sucessfully enabled/disabled.
  1985.  * TCL_ERROR if an error occurred or if facility is not available.
  1986.  *
  1987.  * Side effects:
  1988.  * None.
  1989.  *
  1990.  *----------------------------------------------------------------------
  1991.  */
  1992. static int TkMacOSXAntialiasedTextEnabled = FALSE;
  1993. static char *
  1994. TkMacOSXAntialiasedTextVariableProc(
  1995.     ClientData clientData,
  1996.     Tcl_Interp *interp,
  1997.     const char *name1,
  1998.     const char *name2,
  1999.     int flags)
  2000. {
  2001.     TkMacOSXUseAntialiasedText(interp, TkMacOSXAntialiasedTextEnabled);
  2002.     return (char *) NULL;
  2003. }
  2004. int
  2005. TkMacOSXUseAntialiasedText(
  2006.     Tcl_Interp *interp,
  2007.     int enable)
  2008. {
  2009.     static Boolean initialized = FALSE;
  2010.     static UInt32 (*swaptextflags)(UInt32) = NULL;
  2011.     if(!initialized) {
  2012. swaptextflags = TkMacOSXGetNamedSymbol("QD", "_QDSwapTextFlags");
  2013. if (!swaptextflags) {
  2014.     swaptextflags = TkMacOSXGetNamedSymbol("QD", "_SwapQDTextFlags");
  2015. }
  2016. initialized = TRUE;
  2017. TkMacOSXAntialiasedTextEnabled = (swaptextflags ? enable : FALSE);
  2018. if (Tcl_CreateNamespace(interp, "::tk::mac", NULL, NULL) == NULL) {
  2019.     Tcl_ResetResult(interp);
  2020. }
  2021. if (Tcl_TraceVar(interp, "::tk::mac::antialiasedtext",
  2022. TCL_GLOBAL_ONLY | TCL_TRACE_WRITES,
  2023. TkMacOSXAntialiasedTextVariableProc, NULL) != TCL_OK) {
  2024.     Tcl_ResetResult(interp);
  2025. }
  2026. if (Tcl_LinkVar(interp, "::tk::mac::antialiasedtext",
  2027. (char *) &TkMacOSXAntialiasedTextEnabled,
  2028. TCL_LINK_BOOLEAN) != TCL_OK) {
  2029.     Tcl_ResetResult(interp);
  2030. }
  2031.     }
  2032.     if (swaptextflags) {
  2033. swaptextflags(enable ? kQDUseCGTextRendering | kQDUseCGTextMetrics
  2034. : kQDUseTrueTypeScalerGlyphs);
  2035. TkMacOSXAntialiasedTextEnabled = enable;
  2036. return TCL_OK;
  2037.     } else {
  2038. TkMacOSXAntialiasedTextEnabled = FALSE;
  2039. return TCL_ERROR;
  2040.     }
  2041. }