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