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

通讯编程

开发平台:

Visual C++

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