tk.git - Tk is a free and open-source, cross-platform widget toolkit that provides a library of basic elements of GUI widgets for building a graphical user interface (GUI) in many programming languages.
Tk is a free and open-source, cross-platform widget toolkit that provides a library of basic elements of GUI widgets for building a graphical user interface (GUI) in many programming languages.
/* * tkMacFont.c -- * * Contains the Macintosh implementation of the platform-independant * font package interface. * * Copyright (c) 1990-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: tkMacFont.c,v 1.8 2002/10/09 11:56:43 das Exp $ */#include <Windows.h>#include <Strings.h>#include <Fonts.h>#include <Script.h>#include <Resources.h>#include <TextUtils.h>#include"tkMacInt.h"#include"tkFont.h"/* * For doing things with Mac strings and Fixed numbers. This probably should move * the mac header file. */#ifndef StrLength#define StrLength(s) (*((unsigned char *) (s)))#endif#ifndef StrBody#define StrBody(s) ((char *) (s) + 1)#endif#define pstrcmp(s1, s2) RelString((s1), (s2), 1, 1)#define pstrcasecmp(s1, s2) RelString((s1), (s2), 0, 1)#ifndef Fixed2Int#define Fixed2Int(f) ((f) >> 16)#define Int2Fixed(i) ((i) << 16)#endif/* * The preferred font encodings. */static CONST char*encodingList[] = {"macRoman","macJapan", NULL
};/* * The following structures are used to map the script/language codes of a * font to the name that should be passed to Tcl_GetTextEncoding() to obtain * the encoding for that font. The set of numeric constants is fixed and * defined by Apple. */static TkStateMap scriptMap[] = {{smRoman,"macRoman"},{smJapanese,"macJapan"},{smTradChinese,"macChinese"},{smKorean,"macKorean"},{smArabic,"macArabic"},{smHebrew,"macHebrew"},{smGreek,"macGreek"},{smCyrillic,"macCyrillic"},{smRSymbol,"macRSymbol"},{smDevanagari,"macDevanagari"},{smGurmukhi,"macGurmukhi"},{smGujarati,"macGujarati"},{smOriya,"macOriya"},{smBengali,"macBengali"},{smTamil,"macTamil"},{smTelugu,"macTelugu"},{smKannada,"macKannada"},{smMalayalam,"macMalayalam"},{smSinhalese,"macSinhalese"},{smBurmese,"macBurmese"},{smKhmer,"macKhmer"},{smThai,"macThailand"},{smLaotian,"macLaos"},{smGeorgian,"macGeorgia"},{smArmenian,"macArmenia"},{smSimpChinese,"macSimpChinese"},{smTibetan,"macTIbet"},{smMongolian,"macMongolia"},{smGeez,"macEthiopia"},{smEastEurRoman,"macCentEuro"},{smVietnamese,"macVietnam"},{smExtArabic,"macSindhi"},{NULL, NULL}};static TkStateMap romanMap[] = {{langCroatian,"macCroatian"},{langSlovenian,"macCroatian"},{langIcelandic,"macIceland"},{langRomanian,"macRomania"},{langTurkish,"macTurkish"},{langGreek,"macGreek"},{NULL, NULL}};static TkStateMap cyrillicMap[] = {{langUkrainian,"macUkraine"},{langBulgarian,"macBulgaria"},{NULL, NULL}};/* * The following structure represents a font family. It is assumed that * all screen fonts constructed from the same "font family" share certain * properties; all screen fonts with the same "font family" point to a * shared instance of this structure. The most important shared property * is the character existence metrics, used to determine if a screen font * can display a given Unicode character. * * Under Macintosh, a "font family" is uniquely identified by its face number. */#define FONTMAP_SHIFT 10#define FONTMAP_PAGES (1 << (sizeof(Tcl_UniChar) * 8 - FONTMAP_SHIFT))#define FONTMAP_BITSPERPAGE (1 << FONTMAP_SHIFT)typedefstruct FontFamily {struct FontFamily *nextPtr;/* Next in list of all known font families. */int refCount;/* How many SubFonts are referring to this * FontFamily. When the refCount drops to * zero, this FontFamily may be freed. *//* * Key. */short faceNum;/* Unique face number key for this FontFamily. *//* * Derived properties. */
Tcl_Encoding encoding;/* Encoding for this font family. */int isSymbolFont;/* Non-zero if this is a symbol family. */int isMultiByteFont;/* Non-zero if this is a multi-byte family. */char typeTable[256];/* Table that identfies all lead bytes for a * multi-byte family, used when measuring chars. * If a byte is a lead byte, the value at the * corresponding position in the typeTable is 1, * otherwise 0. If this is a single-byte font, * all entries are 0. */char*fontMap[FONTMAP_PAGES];/* Two-level sparse table used to determine * quickly if the specified character exists. * As characters are encountered, more pages * in this table are dynamically added. The * contents of each page is a bitmask * consisting of FONTMAP_BITSPERPAGE bits, * representing whether this font can be used * to display the given character at the * corresponding bit position. The high bits * of the character are used to pick which * page of the table is used. */} FontFamily;/* * The following structure encapsulates an individual screen font. A font * object is made up of however many SubFonts are necessary to display a * stream of multilingual characters. */typedefstruct SubFont {char**fontMap;/* Pointer to font map from the FontFamily, * cached here to save a dereference. */
FontFamily *familyPtr;/* The FontFamily for this SubFont. */} SubFont;/* * The following structure represents Macintosh's implementation of a font * object. */#define SUBFONT_SPACE 3typedefstruct MacFont {
TkFont font;/* Stuff used by generic font package. Must * be first in structure. */
SubFont staticSubFonts[SUBFONT_SPACE];/* Builtin space for a limited number of * SubFonts. */int numSubFonts;/* Length of following array. */
SubFont *subFontArray;/* Array of SubFonts that have been loaded * in order to draw/measure all the characters * encountered by this font so far. All fonts * start off with one SubFont initialized by * AllocFont() from the original set of font * attributes. Usually points to * staticSubFonts, but may point to malloced * space if there are lots of SubFonts. */short size;/* Font size in pixels, constructed from * font attributes. */short style;/* Style bits, constructed from font * attributes. */} MacFont;/* * The following structure is used to map between the UTF-8 name for a font and * the name that the Macintosh uses to refer to the font, in order to determine * if a font exists. The Macintosh names for fonts are stored in the encoding * of the font itself. */typedefstruct FontNameMap {
Tk_Uid utfName;/* The name of the font in UTF-8. */
StringPtr nativeName;/* The name of the font in the font's encoding. */short faceNum;/* Unique face number for this font. */} FontNameMap;/* * The list of font families that are currently loaded. As screen fonts * are loaded, this list grows to hold information about what characters * exist in each font family. */static FontFamily *fontFamilyList = NULL;/* * Information cached about the system at startup time. */static FontNameMap *gFontNameMap = NULL;static GWorldPtr gWorld = NULL;/* * Procedures used only in this file. */static FontFamily *AllocFontFamily(CONST MacFont *fontPtr,int family);static SubFont *CanUseFallback(MacFont *fontPtr,
CONST char*fallbackName,int ch);static SubFont *CanUseFallbackWithAliases(MacFont *fontPtr,
CONST char*faceName,int ch, Tcl_DString *nameTriedPtr);static SubFont *FindSubFontForChar(MacFont *fontPtr,int ch);static voidFontMapInsert(SubFont *subFontPtr,int ch);static voidFontMapLoadPage(SubFont *subFontPtr,int row);static intFontMapLookup(SubFont *subFontPtr,int ch);static voidFreeFontFamily(FontFamily *familyPtr);static voidInitFont(Tk_Window tkwin,int family,int size,int style, MacFont *fontPtr);static voidInitSubFont(CONST MacFont *fontPtr,int family,
SubFont *subFontPtr);static voidMultiFontDrawText(MacFont *fontPtr,
CONST char*source,int numBytes,int x,int y);static voidReleaseFont(MacFont *fontPtr);static voidReleaseSubFont(SubFont *subFontPtr);static intSeenName(CONST char*name, Tcl_DString *dsPtr);static CONST char*BreakLine(FontFamily *familyPtr,int flags,
CONST char*source,int numBytes,int*widthPtr);static intGetFamilyNum(CONST char*faceName,short*familyPtr);static intGetFamilyOrAliasNum(CONST char*faceName,short*familyPtr);static Tcl_Encoding GetFontEncoding(int faceNum,int allowSymbol,int*isSymbolPtr);static Tk_Uid GetUtfFaceName(StringPtr faceNameStr);/* *------------------------------------------------------------------------- * * TkpFontPkgInit -- * * This procedure is called when an application is created. It * initializes all the structures that are used by the * platform-dependant code on a per application basis. * * Results: * None. * * Side effects: * See comments below. * *------------------------------------------------------------------------- */voidTkpFontPkgInit(mainPtr)
TkMainInfo *mainPtr;/* The application being created. */{
MenuHandle fontMenu;
FontNameMap *tmpFontNameMap, *newFontNameMap, *mapPtr;int i, j, numFonts, fontMapOffset, isSymbol;
Str255 nativeName;
Tcl_DString ds;
Tcl_Encoding encoding;
Tcl_Encoding *encodings;if(gWorld == NULL) {/* * Do the following one time only. */
Rect rect = {0,0,1,1};SetFractEnable(0);/* * Used for saving and restoring state while drawing and measuring. */if(NewGWorld(&gWorld,0, &rect, NULL, NULL,0) != noErr) {panic("TkpFontPkgInit: NewGWorld failed");}/* * The name of each font is stored in the encoding of that font. * How would we translate a name from UTF-8 into the native encoding * of the font unless we knew the encoding of that font? We can't. * So, precompute the UTF-8 and native names of all fonts on the * system. The when the user asks for font by its UTF-8 name, we * lookup the name in that table and really ask for the font by its * native name. Any unknown UTF-8 names will be mapped to the system * font. */
fontMenu =NewMenu('FT',"\px");AppendResMenu(fontMenu,'FONT');
numFonts =CountMItems(fontMenu);
tmpFontNameMap = (FontNameMap *)ckalloc(sizeof(FontNameMap) * numFonts);
encodings = (Tcl_Encoding *)ckalloc(sizeof(Tcl_Encoding) * numFonts);
mapPtr = tmpFontNameMap;for(i =0; i < numFonts; i++) {GetMenuItemText(fontMenu, i +1, nativeName);GetFNum(nativeName, &mapPtr->faceNum);
encodings[i] =GetFontEncoding(mapPtr->faceNum,0, &isSymbol);Tcl_ExternalToUtfDString(encodings[i],StrBody(nativeName),StrLength(nativeName), &ds);
mapPtr->utfName =Tk_GetUid(Tcl_DStringValue(&ds));
mapPtr->nativeName = (StringPtr)ckalloc(StrLength(nativeName) +1);memcpy(mapPtr->nativeName, nativeName,StrLength(nativeName) +1);Tcl_DStringFree(&ds);
mapPtr++;}DisposeMenu(fontMenu);/* * Reorder FontNameMap so fonts with the preferred encodings are at * the front of the list. The relative order of fonts that all have * the same encoding is preserved. Fonts with unknown encodings get * stuck at the end. */
newFontNameMap = (FontNameMap *)ckalloc(sizeof(FontNameMap) * (numFonts +1));
fontMapOffset =0;for(i =0; encodingList[i] != NULL; i++) {
encoding =Tcl_GetEncoding(NULL, encodingList[i]);if(encoding == NULL) {continue;}for(j =0; j < numFonts; j++) {if(encodings[j] == encoding) {
newFontNameMap[fontMapOffset] = tmpFontNameMap[j];
fontMapOffset++;Tcl_FreeEncoding(encodings[j]);
tmpFontNameMap[j].utfName = NULL;}}Tcl_FreeEncoding(encoding);}for(i =0; i < numFonts; i++) {if(tmpFontNameMap[i].utfName != NULL) {
newFontNameMap[fontMapOffset] = tmpFontNameMap[i];
fontMapOffset++;Tcl_FreeEncoding(encodings[i]);}}if(fontMapOffset != numFonts) {panic("TkpFontPkgInit: unexpected number of fonts");}
mapPtr = &newFontNameMap[numFonts];
mapPtr->utfName = NULL;
mapPtr->nativeName = NULL;
mapPtr->faceNum =0;ckfree((char*) tmpFontNameMap);ckfree((char*) encodings);
gFontNameMap = newFontNameMap;}}/* *--------------------------------------------------------------------------- * * TkpGetNativeFont -- * * Map a platform-specific native font name to a TkFont. * * Results: * The return value is a pointer to a TkFont that represents the * native font. If a native font by the given name could not be * found, the return value is NULL. * * Every call to this procedure returns a new TkFont structure, * even if the name has already been seen before. The caller should * call TkpDeleteFont() when the font is no longer needed. * * The caller is responsible for initializing the memory associated * with the generic TkFont when this function returns and releasing * the contents of the generics TkFont before calling TkpDeleteFont(). * * Side effects: * None. * *--------------------------------------------------------------------------- */
TkFont *TkpGetNativeFont(
Tk_Window tkwin,/* For display where font will be used. */
CONST char*name)/* Platform-specific font name. */{short family;
MacFont *fontPtr;if(strcmp(name,"system") ==0) {
family =GetSysFont();}else if(strcmp(name,"application") ==0) {
family =GetAppFont();}else{return NULL;}
fontPtr = (MacFont *)ckalloc(sizeof(MacFont));InitFont(tkwin, family,0,0, fontPtr);return(TkFont *) fontPtr;}/* *--------------------------------------------------------------------------- * * TkpGetFontFromAttributes -- * * Given a desired set of attributes for a font, find a font with * the closest matching attributes. * * Results: * The return value is a pointer to a TkFont that represents the * font with the desired attributes. If a font with the desired * attributes could not be constructed, some other font will be * substituted automatically. * * Every call to this procedure returns a new TkFont structure, * even if the specified attributes have already been seen before. * The caller should call TkpDeleteFont() to free the platform- * specific data when the font is no longer needed. * * The caller is responsible for initializing the memory associated * with the generic TkFont when this function returns and releasing * the contents of the generic TkFont before calling TkpDeleteFont(). * * Side effects: * None. * *--------------------------------------------------------------------------- */
TkFont *TkpGetFontFromAttributes(
TkFont *tkFontPtr,/* If non-NULL, store the information in * this existing TkFont structure, rather than * allocating a new structure to hold the * font; the existing contents of the font * will be released. If NULL, a new TkFont * structure is allocated. */
Tk_Window tkwin,/* For display where font will be used. */
CONST TkFontAttributes *faPtr)/* Set of attributes to match. */{short faceNum, style;int i, j;
CONST char*faceName;char*fallback;char***fallbacks;
MacFont *fontPtr;/* * Algorithm to get the closest font to the one requested. * * try fontname * try all aliases for fontname * foreach fallback for fontname * try the fallback * try all aliases for the fallback */
faceNum =0;
faceName = faPtr->family;if(faceName != NULL) {if(GetFamilyOrAliasNum(faceName, &faceNum) !=0) {goto found;}
fallbacks =TkFontGetFallbacks();for(i =0; fallbacks[i] != NULL; i++) {for(j =0; (fallback = fallbacks[i][j]) != NULL; j++) {if(strcasecmp(faceName, fallback) ==0) {for(j =0; (fallback = fallbacks[i][j]) != NULL; j++) {if(GetFamilyOrAliasNum(fallback, &faceNum)) {goto found;}}}break;}}}
found:
style =0;if(faPtr->weight != TK_FW_NORMAL) {
style |= bold;}if(faPtr->slant != TK_FS_ROMAN) {
style |= italic;}if(faPtr->underline) {
style |= underline;}if(tkFontPtr == NULL) {
fontPtr = (MacFont *)ckalloc(sizeof(MacFont));}else{
fontPtr = (MacFont *) tkFontPtr;ReleaseFont(fontPtr);}InitFont(tkwin, faceNum, faPtr->size, style, fontPtr);return(TkFont *) fontPtr;}/* *--------------------------------------------------------------------------- * * TkpDeleteFont -- * * Called to release a font allocated by TkpGetNativeFont() or * TkpGetFontFromAttributes(). The caller should have already * released the fields of the TkFont that are used exclusively by * the generic TkFont code. * * Results: * None. * * Side effects: * TkFont is deallocated. * *--------------------------------------------------------------------------- */voidTkpDeleteFont(
TkFont *tkFontPtr)/* Token of font to be deleted. */{
MacFont *fontPtr;
fontPtr = (MacFont *) tkFontPtr;ReleaseFont(fontPtr);}/* *--------------------------------------------------------------------------- * * TkpGetFontFamilies -- * * Return information about the font families that are available * on the display of the given window. * * Results: * Modifies interp's result object to hold a list of all the available * font families. * * Side effects: * None. * *--------------------------------------------------------------------------- */voidTkpGetFontFamilies(
Tcl_Interp *interp,/* Interp to hold result. */
Tk_Window tkwin)/* For display to query. */{
FontNameMap *mapPtr;
Tcl_Obj *resultPtr, *strPtr;
resultPtr =Tcl_GetObjResult(interp);for(mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) {
strPtr =Tcl_NewStringObj(mapPtr->utfName, -1);Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);}}/* *------------------------------------------------------------------------- * * TkpGetSubFonts -- * * A function used by the testing package for querying the actual * screen fonts that make up a font object. * * Results: * Modifies interp's result object to hold a list containing the * names of the screen fonts that make up the given font object. * * Side effects: * None. * *------------------------------------------------------------------------- */voidTkpGetSubFonts(interp, tkfont)
Tcl_Interp *interp;/* Interp to hold result. */
Tk_Font tkfont;/* Font object to query. */{int i;
Tcl_Obj *resultPtr, *strPtr;
MacFont *fontPtr;
FontFamily *familyPtr;
Str255 nativeName;
resultPtr =Tcl_GetObjResult(interp);
fontPtr = (MacFont *) tkfont;for(i =0; i < fontPtr->numSubFonts; i++) {
familyPtr = fontPtr->subFontArray[i].familyPtr;GetFontName(familyPtr->faceNum, nativeName);
strPtr =Tcl_NewStringObj(GetUtfFaceName(nativeName), -1);Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);}}/* *--------------------------------------------------------------------------- * * Tk_MeasureChars -- * * Determine the number of characters from the string that will fit * in the given horizontal span. The measurement is done under the * assumption that Tk_DrawChars() will be used to actually display * the characters. * * Results: * The return value is the number of bytes from source that * fit into the span that extends from 0 to maxLength. *lengthPtr is * filled with the x-coordinate of the right edge of the last * character that did fit. * * Side effects: * None. * *--------------------------------------------------------------------------- */intTk_MeasureChars(
Tk_Font tkfont,/* Font in which characters will be drawn. */
CONST char*source,/* UTF-8 string to be displayed. Need not be * '\0' terminated. */int numBytes,/* Maximum number of bytes to consider * from source string. */int maxLength,/* If >= 0, maxLength specifies the longest * permissible line length; don't consider any * character that would cross this * x-position. If < 0, then line length is * unbounded and the flags argument is * ignored. */int flags,/* Various flag bits OR-ed together: * TK_PARTIAL_OK means include the last char * which only partially fit on this line. * TK_WHOLE_WORDS means stop on a word * boundary, if possible. * TK_AT_LEAST_ONE means return at least one * character even if no characters fit. */int*lengthPtr)/* Filled with x-location just after the * terminating character. */{
MacFont *fontPtr;
FontFamily *lastFamilyPtr;
CGrafPtr saveWorld;
GDHandle saveDevice;int curX, curByte;/* * According to "Inside Macintosh: Text", the Macintosh may * automatically substitute * ligatures or context-sensitive presentation forms when * measuring/displaying text within a font run. We cannot safely * measure individual characters and add up the widths w/o errors. * However, if we convert a range of text from UTF-8 to, say, * Shift-JIS, and get the offset into the Shift-JIS string as to * where a word or line break would occur, then can we map that * number back to UTF-8? */
fontPtr = (MacFont *) tkfont;GetGWorld(&saveWorld, &saveDevice);SetGWorld(gWorld, NULL);TextSize(fontPtr->size);TextFace(fontPtr->style);
lastFamilyPtr = fontPtr->subFontArray[0].familyPtr;if(numBytes ==0) {
curX =0;
curByte =0;}else if(maxLength <0) {
CONST char*p, *end, *next;
Tcl_UniChar ch;
FontFamily *thisFamilyPtr;
Tcl_DString runString;/* * A three step process: * 1. Find a contiguous range of characters that can all be * represented by a single screen font. * 2. Convert those chars to the encoding of that font. * 3. Measure converted chars. */
curX =0;
end = source + numBytes;for(p = source; p < end; ) {
next = p +Tcl_UtfToUniChar(p, &ch);
thisFamilyPtr =FindSubFontForChar(fontPtr, ch)->familyPtr;if(thisFamilyPtr != lastFamilyPtr) {TextFont(lastFamilyPtr->faceNum);Tcl_UtfToExternalDString(lastFamilyPtr->encoding, source,
p - source, &runString);
curX +=TextWidth(Tcl_DStringValue(&runString),0,Tcl_DStringLength(&runString));Tcl_DStringFree(&runString);
lastFamilyPtr = thisFamilyPtr;
source = p;}
p = next;}TextFont(lastFamilyPtr->faceNum);Tcl_UtfToExternalDString(lastFamilyPtr->encoding, source, p - source,&runString);
curX +=TextWidth(Tcl_DStringValue(&runString),0,Tcl_DStringLength(&runString));Tcl_DStringFree(&runString);
curByte = numBytes;}else{
CONST char*p, *end, *next, *sourceOrig;int widthLeft;
FontFamily *thisFamilyPtr;
Tcl_UniChar ch;
CONST char*rest;/* * How many chars will fit in the space allotted? */if(maxLength >32767) {
maxLength =32767;}
widthLeft = maxLength;
sourceOrig = source;
end = source + numBytes;for(p = source; p < end; p = next) {
next = p +Tcl_UtfToUniChar(p, &ch);
thisFamilyPtr =FindSubFontForChar(fontPtr, ch)->familyPtr;if(thisFamilyPtr != lastFamilyPtr) {if(p > source) {
rest =BreakLine(lastFamilyPtr, flags, source,
p - source, &widthLeft);
flags &= ~TK_AT_LEAST_ONE;if(rest != NULL) {
p = source;break;}}
lastFamilyPtr = thisFamilyPtr;
source = p;}}if(p > source) {
rest =BreakLine(lastFamilyPtr, flags, source, p - source,&widthLeft);}if(rest == NULL) {
curByte = numBytes;}else{
curByte = rest - sourceOrig;}
curX = maxLength - widthLeft;}SetGWorld(saveWorld, saveDevice);*lengthPtr = curX;return curByte;}/* *--------------------------------------------------------------------------- * * BreakLine -- * * Determine where the given line of text should be broken so that it * fits in the specified range. Before calling this function, the * font values and graphics port must be set. * * Results: * The return value is NULL if the specified range is larger that the * space the text needs, and *widthLeftPtr is filled with how much * space is left in the range after measuring the whole text buffer. * Otherwise, the return value is a pointer into the text buffer that * indicates where the line should be broken (up to, but not including * that character), and *widthLeftPtr is filled with how much space is * left in the range after measuring up to that character. * * Side effects: * None. * *--------------------------------------------------------------------------- */static CONST char*BreakLine(
FontFamily *familyPtr,/* FontFamily that describes the font values * that are already selected into the graphics * port. */int flags,/* Various flag bits OR-ed together: * TK_PARTIAL_OK means include the last char * which only partially fit on this line. * TK_WHOLE_WORDS means stop on a word * boundary, if possible. * TK_AT_LEAST_ONE means return at least one * character even if no characters fit. */
CONST char*source,/* UTF-8 string to be displayed. Need not be * '\0' terminated. */int numBytes,/* Maximum number of bytes to consider * from source string. */int*widthLeftPtr)/* On input, specifies size of range into * which characters from source buffer should * be fit. On output, filled with how much * space is left after fitting as many * characters as possible into the range. * Result may be negative if TK_AT_LEAST_ONE * was specified in the flags argument. */{
Fixed pixelWidth, widthLeft;
StyledLineBreakCode breakCode;
Tcl_DString runString;long textOffset;
Boolean leadingEdge;
Point point;int charOffset, thisCharWasDoubleByte;char*p, *end, *typeTable;TextFont(familyPtr->faceNum);Tcl_UtfToExternalDString(familyPtr->encoding, source, numBytes,&runString);
pixelWidth =Int2Fixed(*widthLeftPtr) +1;if(flags & TK_WHOLE_WORDS) {
textOffset = (flags & TK_AT_LEAST_ONE);
widthLeft = pixelWidth;
breakCode =StyledLineBreak(Tcl_DStringValue(&runString),Tcl_DStringLength(&runString),0,Tcl_DStringLength(&runString),0, &widthLeft, &textOffset);if(breakCode != smBreakOverflow) {/* * StyledLineBreak includes all the space characters at the end of * line that we want to suppress. */
textOffset =VisibleLength(Tcl_DStringValue(&runString), textOffset);goto getoffset;}}else{
point.v =1;
point.h =1;
textOffset =PixelToChar(Tcl_DStringValue(&runString),Tcl_DStringLength(&runString),0, pixelWidth, &leadingEdge,&widthLeft, smOnlyStyleRun, point, point);if(Fixed2Int(widthLeft) <0) {goto getoffset;}}*widthLeftPtr =Fixed2Int(widthLeft);Tcl_DStringFree(&runString);return NULL;/* * The conversion routine that converts UTF-8 to the target encoding * must map one UTF-8 character to exactly one encoding-specific * character, so that the following algorithm works: * * 1. Get byte offset of where line should be broken. * 2. Get char offset corresponding to that byte offset. * 3. Map that char offset to byte offset in UTF-8 string. */
getoffset:
thisCharWasDoubleByte =0;if(familyPtr->isMultiByteFont ==0) {
charOffset = textOffset;}else{
charOffset =0;
typeTable = familyPtr->typeTable;
p =Tcl_DStringValue(&runString);
end = p + textOffset;
thisCharWasDoubleByte = typeTable[*((unsigned char*) p)];for( ; p < end; p++) {
thisCharWasDoubleByte = typeTable[*((unsigned char*) p)];
p += thisCharWasDoubleByte;
charOffset++;}}if((flags & TK_WHOLE_WORDS) ==0) {if((flags & TK_PARTIAL_OK) && (leadingEdge !=0)) {
textOffset += thisCharWasDoubleByte;
textOffset++;
charOffset++;}else if(((flags & TK_PARTIAL_OK) ==0) && (leadingEdge ==0)) {
textOffset -= thisCharWasDoubleByte;
textOffset--;
charOffset--;}}if((textOffset ==0) && (Tcl_DStringLength(&runString) >0)&& (flags & TK_AT_LEAST_ONE)) {
p =Tcl_DStringValue(&runString);
textOffset += familyPtr->typeTable[*((unsigned char*) p)];
textOffset++;
charOffset++;}*widthLeftPtr =Fixed2Int(pixelWidth)-TextWidth(Tcl_DStringValue(&runString),0, textOffset);Tcl_DStringFree(&runString);returnTcl_UtfAtIndex(source, charOffset);}/* *--------------------------------------------------------------------------- * * Tk_DrawChars -- * * Draw a string of characters on the screen. * * Results: * None. * * Side effects: * Information gets drawn on the screen. * *--------------------------------------------------------------------------- */voidTk_DrawChars(
Display *display,/* Display on which to draw. */
Drawable drawable,/* Window or pixmap in which to draw. */
GC gc,/* Graphics context for drawing characters. */
Tk_Font tkfont,/* Font in which characters will be drawn; * must be the same as font used in GC. */
CONST char*source,/* UTF-8 string to be displayed. Need not be * '\0' terminated. All Tk meta-characters * (tabs, control characters, and newlines) * should be stripped out of the string that * is passed to this function. If they are * not stripped out, they will be displayed as * regular printing characters. */int numBytes,/* Number of bytes in string. */int x,int y)/* Coordinates at which to place origin of * string when drawing. */{
MacFont *fontPtr;
MacDrawable *macWin;
RGBColor macColor, origColor;
GWorldPtr destPort;
CGrafPtr saveWorld;
GDHandle saveDevice;short txFont, txFace, txSize;
BitMapPtr stippleMap;
fontPtr = (MacFont *) tkfont;
macWin = (MacDrawable *) drawable;
destPort =TkMacGetDrawablePort(drawable);GetGWorld(&saveWorld, &saveDevice);SetGWorld(destPort, NULL);TkMacSetUpClippingRgn(drawable);TkMacSetUpGraphicsPort(gc);
txFont = tcl_macQdPtr->thePort->txFont;
txFace = tcl_macQdPtr->thePort->txFace;
txSize = tcl_macQdPtr->thePort->txSize;GetForeColor(&origColor);if((gc->fill_style == FillStippled
|| gc->fill_style == FillOpaqueStippled)&& gc->stipple != None) {
Pixmap pixmap;
GWorldPtr bufferPort;
stippleMap =TkMacMakeStippleMap(drawable, gc->stipple);
pixmap =Tk_GetPixmap(display, drawable,
stippleMap->bounds.right, stippleMap->bounds.bottom,0);
bufferPort =TkMacGetDrawablePort(pixmap);SetGWorld(bufferPort, NULL);if(TkSetMacColor(gc->foreground, &macColor) ==true) {RGBForeColor(&macColor);}ShowPen();FillRect(&stippleMap->bounds, &tcl_macQdPtr->white);MultiFontDrawText(fontPtr, source, numBytes,0,0);SetGWorld(destPort, NULL);CopyDeepMask(&((GrafPtr) bufferPort)->portBits, stippleMap,&((GrafPtr) destPort)->portBits, &stippleMap->bounds,&stippleMap->bounds, &((GrafPtr) destPort)->portRect,
srcOr, NULL);/* TODO: this doesn't work quite right - it does a blend. you can't * draw white text when you have a stipple. */Tk_FreePixmap(display, pixmap);ckfree(stippleMap->baseAddr);ckfree((char*)stippleMap);}else{if(TkSetMacColor(gc->foreground, &macColor) ==true) {RGBForeColor(&macColor);}ShowPen();MultiFontDrawText(fontPtr, source, numBytes, macWin->xOff + x,
macWin->yOff + y);}TextFont(txFont);TextSize(txSize);TextFace(txFace);RGBForeColor(&origColor);SetGWorld(saveWorld, saveDevice);}/* *------------------------------------------------------------------------- * * MultiFontDrawText -- * * Helper function for Tk_DrawChars. Draws characters, using the * various screen fonts in fontPtr to draw multilingual characters. * Note: No bidirectional support. * * Results: * None. * * Side effects: * Information gets drawn on the screen. * Contents of fontPtr may be modified if more subfonts were loaded * in order to draw all the multilingual characters in the given * string. * *------------------------------------------------------------------------- */static voidMultiFontDrawText(
MacFont *fontPtr,/* Contains set of fonts to use when drawing * following string. */
CONST char*source,/* Potentially multilingual UTF-8 string. */int numBytes,/* Length of string in bytes. */int x,int y)/* Coordinates at which to place origin * * of string when drawing. */{
FontFamily *lastFamilyPtr, *thisFamilyPtr;
Tcl_DString runString;
CONST char*p, *end, *next;
Tcl_UniChar ch;TextSize(fontPtr->size);TextFace(fontPtr->style);
lastFamilyPtr = fontPtr->subFontArray[0].familyPtr;
end = source + numBytes;for(p = source; p < end; ) {
next = p +Tcl_UtfToUniChar(p, &ch);
thisFamilyPtr =FindSubFontForChar(fontPtr, ch)->familyPtr;if(thisFamilyPtr != lastFamilyPtr) {if(p > source) {TextFont(lastFamilyPtr->faceNum);Tcl_UtfToExternalDString(lastFamilyPtr->encoding, source,
p - source, &runString);MoveTo((short) x, (short) y);DrawText(Tcl_DStringValue(&runString),0,Tcl_DStringLength(&runString));
x +=TextWidth(Tcl_DStringValue(&runString),0,Tcl_DStringLength(&runString));Tcl_DStringFree(&runString);
source = p;}
lastFamilyPtr = thisFamilyPtr;}
p = next;}if(p > source) {TextFont(thisFamilyPtr->faceNum);Tcl_UtfToExternalDString(lastFamilyPtr->encoding, source,
p - source, &runString);MoveTo((short) x, (short) y);DrawText(Tcl_DStringValue(&runString),0,Tcl_DStringLength(&runString));Tcl_DStringFree(&runString);}}/* *--------------------------------------------------------------------------- * * TkMacIsCharacterMissing -- * * Given a tkFont and a character determines whether the character has * a glyph defined in the font or not. Note that this is potentially * not compatible with Mac OS 8 as it looks at the font handle * structure directly. Looks into the character array of the font * handle to determine whether the glyph is defined or not. * * Results: * Returns a 1 if the character is missing, a 0 if it is not. * * Side effects: * None. * *--------------------------------------------------------------------------- */intTkMacIsCharacterMissing(
Tk_Font tkfont,/* The font we are looking in. */unsigned int searchChar)/* The character we are looking for. */{
MacFont *fontPtr = (MacFont *) tkfont;
FMInput fm;
FontRec **fontRecHandle;
fm.family = fontPtr->subFontArray[0].familyPtr->faceNum;
fm.size = fontPtr->size;
fm.face = fontPtr->style;
fm.needBits =0;
fm.device =0;
fm.numer.h = fm.numer.v = fm.denom.h = fm.denom.v =1;#if !defined(UNIVERSAL_INTERFACES_VERSION) || (UNIVERSAL_INTERFACES_VERSION < 0x0300)
fontRecHandle = (FontRec **)FMSwapFont(&fm)->fontResult;#else
fontRecHandle = (FontRec **)FMSwapFont(&fm)->fontHandle;#endifreturn*(short*) ((long) &(*fontRecHandle)->owTLoc
+ ((long)((*fontRecHandle)->owTLoc + searchChar
- (*fontRecHandle)->firstChar) *sizeof(short))) == -1;}/* *--------------------------------------------------------------------------- * * InitFont -- * * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes(). * Initializes the memory for a MacFont that wraps the platform-specific * data. * * The caller is responsible for initializing the fields of the * TkFont that are used exclusively by the generic TkFont code, and * for releasing those fields before calling TkpDeleteFont(). * * Results: * Fills the MacFont structure. * * Side effects: * Memory allocated. * *--------------------------------------------------------------------------- */static voidInitFont(
Tk_Window tkwin,/* For display where font will be used. */int faceNum,/* Macintosh font number. */int size,/* Point size for Macintosh font. */int style,/* Macintosh style bits. */
MacFont *fontPtr)/* Filled with information constructed from * the above arguments. */{
Str255 nativeName;
FontInfo fi;
TkFontAttributes *faPtr;
TkFontMetrics *fmPtr;
CGrafPtr saveWorld;
GDHandle saveDevice;short pixels;if(size ==0) {
size = -GetDefFontSize();}
pixels = (short)TkFontGetPixels(tkwin, size);GetGWorld(&saveWorld, &saveDevice);SetGWorld(gWorld, NULL);TextFont(faceNum);TextSize(pixels);TextFace(style);GetFontInfo(&fi);GetFontName(faceNum, nativeName);
fontPtr->font.fid = (Font) fontPtr;
faPtr = &fontPtr->font.fa;
faPtr->family =GetUtfFaceName(nativeName);
faPtr->size =TkFontGetPoints(tkwin, size);
faPtr->weight = (style & bold) ? TK_FW_BOLD : TK_FW_NORMAL;
faPtr->slant = (style & italic) ? TK_FS_ITALIC : TK_FS_ROMAN;
faPtr->underline = ((style & underline) !=0);
faPtr->overstrike =0;
fmPtr = &fontPtr->font.fm;
fmPtr->ascent = fi.ascent;
fmPtr->descent = fi.descent;
fmPtr->maxWidth = fi.widMax;
fmPtr->fixed = (CharWidth('i') ==CharWidth('w'));
fontPtr->size = pixels;
fontPtr->style = (short) style;
fontPtr->numSubFonts =1;
fontPtr->subFontArray = fontPtr->staticSubFonts;InitSubFont(fontPtr, faceNum, &fontPtr->subFontArray[0]);SetGWorld(saveWorld, saveDevice);}/* *------------------------------------------------------------------------- * * ReleaseFont -- * * Called to release the Macintosh-specific contents of a TkFont. * The caller is responsible for freeing the memory used by the * font itself. * * Results: * None. * * Side effects: * Memory is freed. * *--------------------------------------------------------------------------- */static voidReleaseFont(
MacFont *fontPtr)/* The font to delete. */{int i;for(i =0; i < fontPtr->numSubFonts; i++) {ReleaseSubFont(&fontPtr->subFontArray[i]);}if(fontPtr->subFontArray != fontPtr->staticSubFonts) {ckfree((char*) fontPtr->subFontArray);}}/* *------------------------------------------------------------------------- * * InitSubFont -- * * Wrap a screen font and load the FontFamily that represents * it. Used to prepare a SubFont so that characters can be mapped * from UTF-8 to the charset of the font. * * Results: * The subFontPtr is filled with information about the font. * * Side effects: * None. * *------------------------------------------------------------------------- */static voidInitSubFont(
CONST MacFont *fontPtr,/* Font object in which the SubFont will be * used. */int faceNum,/* The font number. */
SubFont *subFontPtr)/* Filled with SubFont constructed from * above attributes. */{
subFontPtr->familyPtr =AllocFontFamily(fontPtr, faceNum);
subFontPtr->fontMap = subFontPtr->familyPtr->fontMap;}/* *------------------------------------------------------------------------- * * ReleaseSubFont -- * * Called to release the contents of a SubFont. The caller is * responsible for freeing the memory used by the SubFont itself. * * Results: * None. * * Side effects: * Memory and resources are freed. * *--------------------------------------------------------------------------- */static voidReleaseSubFont(
SubFont *subFontPtr)/* The SubFont to delete. */{FreeFontFamily(subFontPtr->familyPtr);}/* *------------------------------------------------------------------------- * * AllocFontFamily -- * * Find the FontFamily structure associated with the given font * family. The information should be stored by the caller in a * SubFont and used when determining if that SubFont supports a * character. * * Results: * A pointer to a FontFamily. The reference count in the FontFamily * is automatically incremented. When the SubFont is released, the * reference count is decremented. When no SubFont is using this * FontFamily, it may be deleted. * * Side effects: * A new FontFamily structure will be allocated if this font family * has not been seen. * *------------------------------------------------------------------------- */static FontFamily *AllocFontFamily(
CONST MacFont *fontPtr,/* Font object in which the FontFamily will * be used. */int faceNum)/* The font number. */{
FontFamily *familyPtr;int i;
familyPtr = fontFamilyList;for(; familyPtr != NULL; familyPtr = familyPtr->nextPtr) {if(familyPtr->faceNum == faceNum) {
familyPtr->refCount++;return familyPtr;}}
familyPtr = (FontFamily *)ckalloc(sizeof(FontFamily));memset(familyPtr,0,sizeof(FontFamily));
familyPtr->nextPtr = fontFamilyList;
fontFamilyList = familyPtr;/* * Set key for this FontFamily. */
familyPtr->faceNum = faceNum;/* * An initial refCount of 2 means that FontFamily information will * persist even when the SubFont that loaded the FontFamily is released. * Change it to 1 to cause FontFamilies to be unloaded when not in use. */
familyPtr->refCount =2;
familyPtr->encoding =GetFontEncoding(faceNum,1, &familyPtr->isSymbolFont);
familyPtr->isMultiByteFont =0;FillParseTable(familyPtr->typeTable,FontToScript(faceNum));for(i =0; i <256; i++) {if(familyPtr->typeTable[i] !=0) {
familyPtr->isMultiByteFont =1;break;}}return familyPtr;}/* *------------------------------------------------------------------------- * * FreeFontFamily -- * * Called to free a FontFamily when the SubFont is finished using it. * Frees the contents of the FontFamily and the memory used by the * FontFamily itself. * * Results: * None. * * Side effects: * None. * *------------------------------------------------------------------------- */static voidFreeFontFamily(
FontFamily *familyPtr)/* The FontFamily to delete. */{
FontFamily **familyPtrPtr;int i;if(familyPtr == NULL) {return;}
familyPtr->refCount--;if(familyPtr->refCount >0) {return;}Tcl_FreeEncoding(familyPtr->encoding);for(i =0; i < FONTMAP_PAGES; i++) {if(familyPtr->fontMap[i] != NULL) {ckfree((char*) familyPtr->fontMap[i]);}}/* * Delete from list. */for(familyPtrPtr = &fontFamilyList; ; ) {if(*familyPtrPtr == familyPtr) {*familyPtrPtr = familyPtr->nextPtr;break;}
familyPtrPtr = &(*familyPtrPtr)->nextPtr;}ckfree((char*) familyPtr);}/* *------------------------------------------------------------------------- * * FindSubFontForChar -- * * Determine which physical screen font is necessary to use to * display the given character. If the font object does not have * a screen font that can display the character, another screen font * may be loaded into the font object, following a set of preferred * fallback rules. * * Results: * The return value is the SubFont to use to display the given * character. * * Side effects: * The contents of fontPtr are modified to cache the results * of the lookup and remember any SubFonts that were dynamically * loaded. * *------------------------------------------------------------------------- */static SubFont *FindSubFontForChar(
MacFont *fontPtr,/* The font object with which the character * will be displayed. */int ch)/* The Unicode character to be displayed. */{int i, j, k;
CONST char*fallbackName;char**aliases;
SubFont *subFontPtr;
FontNameMap *mapPtr;
Tcl_DString faceNames;char***fontFallbacks;char**anyFallbacks;if(FontMapLookup(&fontPtr->subFontArray[0], ch)) {return&fontPtr->subFontArray[0];}for(i =1; i < fontPtr->numSubFonts; i++) {if(FontMapLookup(&fontPtr->subFontArray[i], ch)) {return&fontPtr->subFontArray[i];}}/* * Keep track of all face names that we check, so we don't check some * name multiple times if it can be reached by multiple paths. */Tcl_DStringInit(&faceNames);
aliases =TkFontGetAliasList(fontPtr->font.fa.family);
subFontPtr = NULL;
fontFallbacks =TkFontGetFallbacks();for(i =0; fontFallbacks[i] != NULL; i++) {for(j =0; fontFallbacks[i][j] != NULL; j++) {
fallbackName = fontFallbacks[i][j];if(strcasecmp(fallbackName, fontPtr->font.fa.family) ==0) {/* * If the base font has a fallback... */goto tryfallbacks;}else if(aliases != NULL) {/* * Or if an alias for the base font has a fallback... */for(k =0; aliases[k] != NULL; k++) {if(strcasecmp(aliases[k], fallbackName) ==0) {goto tryfallbacks;}}}}continue;/* * ...then see if we can use one of the fallbacks, or an * alias for one of the fallbacks. */
tryfallbacks:for(j =0; fontFallbacks[i][j] != NULL; j++) {
fallbackName = fontFallbacks[i][j];
subFontPtr =CanUseFallbackWithAliases(fontPtr, fallbackName,
ch, &faceNames);if(subFontPtr != NULL) {goto end;}}}/* * See if we can use something from the global fallback list. */
anyFallbacks =TkFontGetGlobalClass();for(i =0; anyFallbacks[i] != NULL; i++) {
fallbackName = anyFallbacks[i];
subFontPtr =CanUseFallbackWithAliases(fontPtr, fallbackName, ch,&faceNames);if(subFontPtr != NULL) {goto end;}}/* * Try all face names available in the whole system until we * find one that can be used. */for(mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) {
fallbackName = mapPtr->utfName;if(SeenName(fallbackName, &faceNames) ==0) {
subFontPtr =CanUseFallback(fontPtr, fallbackName, ch);if(subFontPtr != NULL) {goto end;}}}
end:Tcl_DStringFree(&faceNames);if(subFontPtr == NULL) {/* * No font can display this character. We will use the base font * and have it display the "unknown" character. */
subFontPtr = &fontPtr->subFontArray[0];FontMapInsert(subFontPtr, ch);}return subFontPtr;}/* *------------------------------------------------------------------------- * * FontMapLookup -- * * See if the screen font can display the given character. * * Results: * The return value is 0 if the screen font cannot display the * character, non-zero otherwise. * * Side effects: * New pages are added to the font mapping cache whenever the * character belongs to a page that hasn't been seen before. * When a page is loaded, information about all the characters on * that page is stored, not just for the single character in * question. * *------------------------------------------------------------------------- */static intFontMapLookup(
SubFont *subFontPtr,/* Contains font mapping cache to be queried * and possibly updated. */int ch)/* Character to be tested. */{int row, bitOffset;
row = ch >> FONTMAP_SHIFT;if(subFontPtr->fontMap[row] == NULL) {FontMapLoadPage(subFontPtr, row);}
bitOffset = ch & (FONTMAP_BITSPERPAGE -1);return(subFontPtr->fontMap[row][bitOffset >>3] >> (bitOffset &7)) &1;}/* *------------------------------------------------------------------------- * * FontMapInsert -- * * Tell the font mapping cache that the given screen font should be * used to display the specified character. This is called when no * font on the system can be be found that can display that * character; we lie to the font and tell it that it can display * the character, otherwise we would end up re-searching the entire * fallback hierarchy every time that character was seen. * * Results: * None. * * Side effects: * New pages are added to the font mapping cache whenever the * character belongs to a page that hasn't been seen before. * When a page is loaded, information about all the characters on * that page is stored, not just for the single character in * question. * *------------------------------------------------------------------------- */static voidFontMapInsert(
SubFont *subFontPtr,/* Contains font mapping cache to be * updated. */int ch)/* Character to be added to cache. */{int row, bitOffset;
row = ch >> FONTMAP_SHIFT;if(subFontPtr->fontMap[row] == NULL) {FontMapLoadPage(subFontPtr, row);}
bitOffset = ch & (FONTMAP_BITSPERPAGE -1);
subFontPtr->fontMap[row][bitOffset >>3] |=1<< (bitOffset &7);}/* *------------------------------------------------------------------------- * * FontMapLoadPage -- * * Load information about all the characters on a given page. * This information consists of one bit per character that indicates * whether the associated HFONT can (1) or cannot (0) display the * characters on the page. * * Results: * None. * * Side effects: * Mempry allocated. * *------------------------------------------------------------------------- */static voidFontMapLoadPage(
SubFont *subFontPtr,/* Contains font mapping cache to be * updated. */int row)/* Index of the page to be loaded into * the cache. */{
FMInput fm;
FontRec *fontRecPtr;short*widths;int i, end, bitOffset, isMultiByteFont;char src[TCL_UTF_MAX];unsigned char buf[16];int srcRead, dstWrote;
Tcl_Encoding encoding;
Handle fHandle;short theID;
ResType theType;
Str255 theName;
subFontPtr->fontMap[row] = (char*)ckalloc(FONTMAP_BITSPERPAGE /8);memset(subFontPtr->fontMap[row],0, FONTMAP_BITSPERPAGE /8);
encoding = subFontPtr->familyPtr->encoding;
fm.family = subFontPtr->familyPtr->faceNum;
fm.size =12;
fm.face =0;
fm.needBits =0;
fm.device =0;
fm.numer.h =1;
fm.numer.v =1;
fm.denom.h =1;
fm.denom.v =1;#if !defined(UNIVERSAL_INTERFACES_VERSION) || (UNIVERSAL_INTERFACES_VERSION < 0x0300)
fHandle =FMSwapFont(&fm)->fontHandle;#else
fHandle =FMSwapFont(&fm)->fontHandle;#endifGetResInfo(fHandle, &theID, &theType, theName);
isMultiByteFont = subFontPtr->familyPtr->isMultiByteFont;if( theType=='sfnt') {/* * Found an outline font which has very complex font record. * Let's just assume *ALL* the characters are allowed. */
end = (row +1) << FONTMAP_SHIFT;for(i = row << FONTMAP_SHIFT; i < end; i++) {if(Tcl_UtfToExternal(NULL, encoding, src,Tcl_UniCharToUtf(i,
src),
TCL_ENCODING_STOPONERROR, NULL, (char*) buf,sizeof(buf),&srcRead, &dstWrote, NULL) == TCL_OK) {
bitOffset = i & (FONTMAP_BITSPERPAGE -1);
subFontPtr->fontMap[row][bitOffset >>3] |=1<< (bitOffset &7);}}}else{/* * Found an old bitmap font which has a well-defined record. * We can check the width table to see which characters exist. */
fontRecPtr = *((FontRec **) fHandle );
widths = (short*) ((long) &fontRecPtr->owTLoc
+ ((long) (fontRecPtr->owTLoc - fontRecPtr->firstChar)*sizeof(short)));
end = (row +1) << FONTMAP_SHIFT;for(i = row << FONTMAP_SHIFT; i < end; i++) {if(Tcl_UtfToExternal(NULL, encoding, src,Tcl_UniCharToUtf(i, src),
TCL_ENCODING_STOPONERROR, NULL, (char*) buf,sizeof(buf),&srcRead, &dstWrote, NULL) == TCL_OK) {if(((isMultiByteFont !=0) && (buf[0] >31))|| (widths[buf[0]] != -1)) {if((buf[0] ==0x11) && (widths[0x12] == -1)) {continue;}/* * Mac's char existence metrics are only for one-byte * characters. If we have a double-byte char, just * assume that the font supports that char if the font's * encoding supports that char. */
bitOffset = i & (FONTMAP_BITSPERPAGE -1);
subFontPtr->fontMap[row][bitOffset >>3] |=1<< (bitOffset &7);}}}}}/* *--------------------------------------------------------------------------- * * CanUseFallbackWithAliases -- * * Helper function for FindSubFontForChar. Determine if the * specified face name (or an alias of the specified face name) * can be used to construct a screen font that can display the * given character. * * Results: * See CanUseFallback(). * * Side effects: * If the name and/or one of its aliases was rejected, the * rejected string is recorded in nameTriedPtr so that it won't * be tried again. * *--------------------------------------------------------------------------- */static SubFont *CanUseFallbackWithAliases(
MacFont *fontPtr,/* The font object that will own the new * screen font. */
CONST char*faceName,/* Desired face name for new screen font. */int ch,/* The Unicode character that the new * screen font must be able to display. */
Tcl_DString *nameTriedPtr)/* Records face names that have already * been tried. It is possible for the same * face name to be queried multiple times when * trying to find a suitable screen font. */{
SubFont *subFontPtr;char**aliases;int i;if(SeenName(faceName, nameTriedPtr) ==0) {
subFontPtr =CanUseFallback(fontPtr, faceName, ch);if(subFontPtr != NULL) {return subFontPtr;}}
aliases =TkFontGetAliasList(faceName);if(aliases != NULL) {for(i =0; aliases[i] != NULL; i++) {if(SeenName(aliases[i], nameTriedPtr) ==0) {
subFontPtr =CanUseFallback(fontPtr, aliases[i], ch);if(subFontPtr != NULL) {return subFontPtr;}}}}return NULL;}/* *--------------------------------------------------------------------------- * * SeenName -- * * Used to determine we have already tried and rejected the given * face name when looking for a screen font that can support some * Unicode character. * * Results: * The return value is 0 if this face name has not already been seen, * non-zero otherwise. * * Side effects: * None. * *--------------------------------------------------------------------------- */static intSeenName(
CONST char*name,/* The name to check. */
Tcl_DString *dsPtr)/* Contains names that have already been * seen. */{
CONST char*seen, *end;
seen =Tcl_DStringValue(dsPtr);
end = seen +Tcl_DStringLength(dsPtr);while(seen < end) {if(strcasecmp(seen, name) ==0) {return1;}
seen +=strlen(seen) +1;}Tcl_DStringAppend(dsPtr, (char*) name, (int) (strlen(name) +1));return0;}/* *------------------------------------------------------------------------- * * CanUseFallback -- * * If the specified physical screen font has not already been loaded * into the font object, determine if the specified physical screen * font can display the given character. * * Results: * The return value is a pointer to a newly allocated SubFont, owned * by the font object. This SubFont can be used to display the given * character. The SubFont represents the screen font with the base set * of font attributes from the font object, but using the specified * font name. NULL is returned if the font object already holds * a reference to the specified physical font or if the specified * physical font cannot display the given character. * * Side effects: * The font object's subFontArray is updated to contain a reference * to the newly allocated SubFont. * *------------------------------------------------------------------------- */static SubFont *CanUseFallback(
MacFont *fontPtr,/* The font object that will own the new * screen font. */
CONST char*faceName,/* Desired face name for new screen font. */int ch)/* The Unicode character that the new * screen font must be able to display. */{int i;
SubFont subFont;short faceNum;if(GetFamilyNum(faceName, &faceNum) ==0) {return NULL;}/* * Skip all fonts we've already used. */for(i =0; i < fontPtr->numSubFonts; i++) {if(faceNum == fontPtr->subFontArray[i].familyPtr->faceNum) {return NULL;}}/* * Load this font and see if it has the desired character. */InitSubFont(fontPtr, faceNum, &subFont);if(((ch <256) && (subFont.familyPtr->isSymbolFont))|| (FontMapLookup(&subFont, ch) ==0)) {ReleaseSubFont(&subFont);return NULL;}if(fontPtr->numSubFonts >= SUBFONT_SPACE) {
SubFont *newPtr;
newPtr = (SubFont *)ckalloc(sizeof(SubFont)* (fontPtr->numSubFonts +1));memcpy((char*) newPtr, fontPtr->subFontArray,
fontPtr->numSubFonts *sizeof(SubFont));if(fontPtr->subFontArray != fontPtr->staticSubFonts) {ckfree((char*) fontPtr->subFontArray);}
fontPtr->subFontArray = newPtr;}
fontPtr->subFontArray[fontPtr->numSubFonts] = subFont;
fontPtr->numSubFonts++;return&fontPtr->subFontArray[fontPtr->numSubFonts -1];}/* *------------------------------------------------------------------------- * * GetFamilyNum -- * * Determines if any physical screen font exists on the system with * the given family name. If the family exists, then it should be * possible to construct some physical screen font with that family * name. * * Results: * The return value is 0 if the specified font family does not exist, * non-zero otherwise. *faceNumPtr is filled with the unique face * number that identifies the screen font, or 0 if the font family * did not exist. * * Side effects: * None. * *------------------------------------------------------------------------- */static intGetFamilyNum(
CONST char*faceName,/* UTF-8 name of font family to query. */short*faceNumPtr)/* Filled with font number for above family. */{
FontNameMap *mapPtr;if(faceName != NULL) {for(mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) {if(strcasecmp(faceName, mapPtr->utfName) ==0) {*faceNumPtr = mapPtr->faceNum;return1;}}}*faceNumPtr =0;return0;}static intGetFamilyOrAliasNum(
CONST char*faceName,/* UTF-8 name of font family to query. */short*faceNumPtr)/* Filled with font number for above family. */{char**aliases;int i;if(GetFamilyNum(faceName, faceNumPtr) !=0) {return1;}
aliases =TkFontGetAliasList(faceName);if(aliases != NULL) {for(i =0; aliases[i] != NULL; i++) {if(GetFamilyNum(aliases[i], faceNumPtr) !=0) {return1;}}}return0;}/* *------------------------------------------------------------------------- * * GetUtfFaceName -- * * Given the native name for a Macintosh font (in which the name of * the font is in the encoding of the font itself), return the UTF-8 * name that corresponds to that font. The specified font name must * refer to a font that actually exists on the machine. * * This function is used to obtain the UTF-8 name when querying the * properties of a Macintosh font object. * * Results: * The return value is a pointer to the UTF-8 of the specified font. * * Side effects: * None. * *------------------------------------------------------------------------ */static Tk_Uid
GetUtfFaceName(
StringPtr nativeName)/* Pascal name for font in native encoding. */{
FontNameMap *mapPtr;for(mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) {if(pstrcmp(nativeName, mapPtr->nativeName) ==0) {return mapPtr->utfName;}}panic("GetUtfFaceName: unexpected nativeName");return NULL;}/* *------------------------------------------------------------------------ * * GetFontEncoding -- * * Return a string that can be passed to Tcl_GetTextEncoding() and * used to convert bytes from UTF-8 into the encoding of the * specified font. * * The desired encoding to use to convert the name of a symbolic * font into UTF-8 is macRoman, while the desired encoding to use * to convert bytes in a symbolic font to UTF-8 is the corresponding * symbolic encoding. Due to this dual interpretatation of symbolic * fonts, the caller can specify what type of encoding to return * should the specified font be symbolic. * * Results: * The return value is a string that specifies the font's encoding. * If the font's encoding could not be identified, NULL is returned. * * Side effects: * None. * *------------------------------------------------------------------------ */static Tcl_Encoding
GetFontEncoding(int faceNum,/* Macintosh font number. */int allowSymbol,/* If non-zero, then the encoding string * for symbol fonts will be the corresponding * symbol encoding. Otherwise, the encoding * string for symbol fonts will be * "macRoman". */int*isSymbolPtr)/* Filled with non-zero if this font is a * symbol font, 0 otherwise. */{
Str255 faceName;int script, lang;char*name;if(allowSymbol !=0) {GetFontName(faceNum, faceName);if(pstrcasecmp(faceName,"\psymbol") ==0) {*isSymbolPtr =1;returnTcl_GetEncoding(NULL,"symbol");}if(pstrcasecmp(faceName,"\pzapf dingbats") ==0) {*isSymbolPtr =1;returnTcl_GetEncoding(NULL,"macDingbats");}}*isSymbolPtr =0;
script =FontToScript(faceNum);
lang =GetScriptVariable(script, smScriptLang);
name = NULL;if(script == smRoman) {
name =TkFindStateString(romanMap, lang);}else if(script == smCyrillic) {
name =TkFindStateString(cyrillicMap, lang);}if(name == NULL) {
name =TkFindStateString(scriptMap, script);}returnTcl_GetEncoding(NULL, name);}