diff options
Diffstat (limited to 'mac/tkMacFont.c')
-rw-r--r-- | mac/tkMacFont.c | 678 |
1 files changed, 678 insertions, 0 deletions
diff --git a/mac/tkMacFont.c b/mac/tkMacFont.c new file mode 100644 index 0000000..8619880 --- /dev/null +++ b/mac/tkMacFont.c @@ -0,0 +1,678 @@ +/* + * 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. + * + * SCCS:@(#) tkMacFont.c 1.52 97/11/20 18:29:51 + */ + +#include <Windows.h> +#include <Strings.h> +#include <Fonts.h> +#include <Resources.h> + +#include "tkMacInt.h" +#include "tkFont.h" +#include "tkPort.h" + +/* + * The following structure represents the Macintosh's' implementation of a + * font. + */ + +typedef struct MacFont { + TkFont font; /* Stuff used by generic font package. Must + * be first in structure. */ + short family; + short size; + short style; +} MacFont; + +static GWorldPtr gWorld = NULL; + +static TkFont * AllocMacFont _ANSI_ARGS_((TkFont *tkfont, + Tk_Window tkwin, int family, int size, int style)); + + +/* + *--------------------------------------------------------------------------- + * + * 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; + + if (strcmp(name, "system") == 0) { + family = GetSysFont(); + } else if (strcmp(name, "application") == 0) { + family = GetAppFont(); + } else { + return NULL; + } + + return AllocMacFont(NULL, tkwin, family, 0, 0); +} + +/* + *--------------------------------------------------------------------------- + * + * 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. */ +{ + char buf[257]; + size_t len; + short family, size, style; + + if (faPtr->family == NULL) { + family = 0; + } else { + CONST char *familyName; + + familyName = faPtr->family; + if (strcasecmp(familyName, "Times New Roman") == 0) { + familyName = "Times"; + } else if (strcasecmp(familyName, "Courier New") == 0) { + familyName = "Courier"; + } else if (strcasecmp(familyName, "Arial") == 0) { + familyName = "Helvetica"; + } + + len = strlen(familyName); + if (len > 255) { + len = 255; + } + buf[0] = (char) len; + memcpy(buf + 1, familyName, len); + buf[len + 1] = '\0'; + GetFNum((StringPtr) buf, &family); + } + + size = faPtr->pointsize; + if (size <= 0) { + size = GetDefFontSize(); + } + + style = 0; + if (faPtr->weight != TK_FW_NORMAL) { + style |= bold; + } + if (faPtr->slant != TK_FS_ROMAN) { + style |= italic; + } + if (faPtr->underline) { + style |= underline; + } + + return AllocMacFont(tkFontPtr, tkwin, family, size, style); +} + +/* + *--------------------------------------------------------------------------- + * + * 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. + * + *--------------------------------------------------------------------------- + */ + +void +TkpDeleteFont( + TkFont *tkFontPtr) /* Token of font to be deleted. */ +{ + ckfree((char *) tkFontPtr); +} + +/* + *--------------------------------------------------------------------------- + * + * TkpGetFontFamilies -- + * + * Return information about the font families that are available + * on the display of the given window. + * + * Results: + * interp->result is modified to hold a list of all the available + * font families. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +void +TkpGetFontFamilies( + Tcl_Interp *interp, /* Interp to hold result. */ + Tk_Window tkwin) /* For display to query. */ +{ + MenuHandle fontMenu; + int i; + char itemText[257]; + + fontMenu = NewMenu(1, "\px"); + AddResMenu(fontMenu, 'FONT'); + + for (i = 1; i < CountMItems(fontMenu); i++) { + /* + * Each item is a pascal string. Convert it to C and append. + */ + GetMenuItemText(fontMenu, i, (unsigned char *) itemText); + itemText[itemText[0] + 1] = '\0'; + Tcl_AppendElement(interp, &itemText[1]); + } + DisposeMenu(fontMenu); +} + + +/* + *--------------------------------------------------------------------------- + * + * 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. + * + *--------------------------------------------------------------------------- + */ + +int +TkMacIsCharacterMissing( + Tk_Font tkfont, /* The font we are looking in. */ + unsigned int searchChar) /* The character we are looking for. */ +{ + MacFont *fontPtr = (MacFont *) tkfont; + FMInput fm; + FontRec **fontRecHandle; + + fm.family = fontPtr->family; + fm.size = fontPtr->size; + fm.face = fontPtr->style; + fm.needBits = 0; + fm.device = 0; + fm.numer.h = fm.numer.v = fm.denom.h = fm.denom.v = 1; + + /* + * This element of the FMOutput structure was changed between the 2.0 & 3.0 + * versions of the Universal Headers. + */ + +#if !defined(UNIVERSAL_INTERFACES_VERSION) || (UNIVERSAL_INTERFACES_VERSION < 0x0300) + fontRecHandle = (FontRec **) FMSwapFont(&fm)->fontResult; +#else + fontRecHandle = (FontRec **) FMSwapFont(&fm)->fontHandle; +#endif + return *(short *) ((long) &(*fontRecHandle)->owTLoc + + ((long)((*fontRecHandle)->owTLoc + searchChar + - (*fontRecHandle)->firstChar) * sizeof(short))) == -1; +} + + +/* + *--------------------------------------------------------------------------- + * + * 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 characters 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. + * + *--------------------------------------------------------------------------- + */ + +int +Tk_MeasureChars( + Tk_Font tkfont, /* Font in which characters will be drawn. */ + CONST char *source, /* Characters to be displayed. Need not be + * '\0' terminated. */ + int numChars, /* Maximum number of characters 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. */ +{ + short staticWidths[128]; + short *widths; + CONST char *p, *term; + int curX, termX, curIdx, sawNonSpace; + MacFont *fontPtr; + CGrafPtr saveWorld; + GDHandle saveDevice; + + if (numChars == 0) { + *lengthPtr = 0; + return 0; + } + + if (gWorld == NULL) { + Rect rect = {0, 0, 1, 1}; + + if (NewGWorld(&gWorld, 0, &rect, NULL, NULL, 0) != noErr) { + panic("NewGWorld failed in Tk_MeasureChars"); + } + } + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(gWorld, NULL); + + fontPtr = (MacFont *) tkfont; + TextFont(fontPtr->family); + TextSize(fontPtr->size); + TextFace(fontPtr->style); + + if (maxLength <= 0) { + *lengthPtr = TextWidth(source, 0, numChars); + SetGWorld(saveWorld, saveDevice); + return numChars; + } + + if (numChars > maxLength) { + /* + * Assume that all chars are at least 1 pixel wide, so there's no + * need to measure more characters than there are pixels. This + * assumption could be refined to an iterative approach that would + * use that as a starting point and try more chars if necessary (if + * there actually were some zero-width chars). + */ + + numChars = maxLength; + } + if (numChars > SHRT_MAX) { + /* + * If they are trying to measure more than 32767 chars at one time, + * it would require several separate measurements. + */ + + numChars = SHRT_MAX; + } + + widths = staticWidths; + if (numChars >= sizeof(staticWidths) / sizeof(staticWidths[0])) { + widths = (short *) ckalloc((numChars + 1) * sizeof(short)); + } + + MeasureText((short) numChars, source, widths); + + if (widths[numChars] <= maxLength) { + curX = widths[numChars]; + curIdx = numChars; + } else { + p = term = source; + curX = termX = 0; + + sawNonSpace = !isspace(UCHAR(*p)); + for (curIdx = 1; ; curIdx++) { + if (isspace(UCHAR(*p))) { + if (sawNonSpace) { + term = p; + termX = widths[curIdx - 1]; + sawNonSpace = 0; + } + } else { + sawNonSpace = 1; + } + if (widths[curIdx] > maxLength) { + curIdx--; + curX = widths[curIdx]; + break; + } + p++; + } + if (flags & TK_PARTIAL_OK) { + curIdx++; + curX = widths[curIdx]; + } + if ((curIdx == 0) && (flags & TK_AT_LEAST_ONE)) { + /* + * The space was too small to hold even one character. Since at + * least one character must always fit on a line, return the width + * of the first character. + */ + + curX = TextWidth(source, 0, 1); + curIdx = 1; + } else if (flags & TK_WHOLE_WORDS) { + /* + * Break at last word that fits on the line. + */ + + if ((flags & TK_AT_LEAST_ONE) && (term == source)) { + /* + * The space was too small to hold an entire word. This + * is the only word on the line, so just return the part of th + * word that fit. + */ + + ; + } else { + curIdx = term - source; + curX = termX; + } + } + } + + if (widths != staticWidths) { + ckfree((char *) widths); + } + + *lengthPtr = curX; + + SetGWorld(saveWorld, saveDevice); + + return curIdx; +} + +/* + *--------------------------------------------------------------------------- + * + * Tk_DrawChars -- + * + * Draw a string of characters on the screen. + * + * Results: + * None. + * + * Side effects: + * Information gets drawn on the screen. + * + *--------------------------------------------------------------------------- + */ + +void +Tk_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, /* Characters to be displayed. Need not be + * '\0' terminated. All Tk meta-characters + * (tabs, control characters, and newlines) + * should be stripped out of the string that + * is passed to this function. If they are + * not stripped out, they will be displayed as + * regular printing characters. */ + int numChars, /* Number of characters in string. */ + int 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); + + TextFont(fontPtr->family); + TextSize(fontPtr->size); + TextFace(fontPtr->style); + + if (TkSetMacColor(gc->foreground, &macColor) == true) { + RGBForeColor(&macColor); + } + + ShowPen(); + MoveTo((short) 0, (short) 0); + FillRect(&stippleMap->bounds, &tcl_macQdPtr->white); + MoveTo((short) x, (short) y); + DrawText(source, 0, (short) numChars); + + 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 { + TextFont(fontPtr->family); + TextSize(fontPtr->size); + TextFace(fontPtr->style); + + if (TkSetMacColor(gc->foreground, &macColor) == true) { + RGBForeColor(&macColor); + } + + ShowPen(); + MoveTo((short) (macWin->xOff + x), (short) (macWin->yOff + y)); + DrawText(source, 0, (short) numChars); + } + + TextFont(txFont); + TextSize(txSize); + TextFace(txFace); + RGBForeColor(&origColor); + SetGWorld(saveWorld, saveDevice); +} + +/* + *--------------------------------------------------------------------------- + * + * AllocMacFont -- + * + * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes(). + * Allocates and intializes the memory for a new TkFont that + * wraps the platform-specific data. + * + * Results: + * Returns pointer to newly constructed TkFont. + * + * 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(). + * + * Side effects: + * Memory allocated. + * + *--------------------------------------------------------------------------- + */ + +static TkFont * +AllocMacFont( + TkFont *tkFontPtr, /* If non-NULL, store the information in + * this existing TkFont structure, rather than + * allocating a new structure to hold the + * font; the existing contents of the font + * will be released. If NULL, a new TkFont + * structure is allocated. */ + Tk_Window tkwin, /* For display where font will be used. */ + int family, /* Macintosh font family. */ + int size, /* Point size for Macintosh font. */ + int style) /* Macintosh style bits. */ +{ + char buf[257]; + FontInfo fi; + MacFont *fontPtr; + TkFontAttributes *faPtr; + TkFontMetrics *fmPtr; + CGrafPtr saveWorld; + GDHandle saveDevice; + + if (gWorld == NULL) { + Rect rect = {0, 0, 1, 1}; + + if (NewGWorld(&gWorld, 0, &rect, NULL, NULL, 0) != noErr) { + panic("NewGWorld failed in AllocMacFont"); + } + } + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(gWorld, NULL); + + if (tkFontPtr == NULL) { + fontPtr = (MacFont *) ckalloc(sizeof(MacFont)); + } else { + fontPtr = (MacFont *) tkFontPtr; + } + + fontPtr->font.fid = (Font) fontPtr; + + faPtr = &fontPtr->font.fa; + GetFontName(family, (StringPtr) buf); + buf[UCHAR(buf[0]) + 1] = '\0'; + faPtr->family = Tk_GetUid(buf + 1); + faPtr->pointsize = size; + faPtr->weight = (style & bold) ? TK_FW_BOLD : TK_FW_NORMAL; + faPtr->slant = (style & italic) ? TK_FS_ITALIC : TK_FS_ROMAN; + faPtr->underline = ((style & underline) != 0); + faPtr->overstrike = 0; + + fmPtr = &fontPtr->font.fm; + TextFont(family); + TextSize(size); + TextFace(style); + GetFontInfo(&fi); + fmPtr->ascent = fi.ascent; + fmPtr->descent = fi.descent; + fmPtr->maxWidth = fi.widMax; + fmPtr->fixed = (CharWidth('i') == CharWidth('w')); + + fontPtr->family = (short) family; + fontPtr->size = (short) size; + fontPtr->style = (short) style; + + SetGWorld(saveWorld, saveDevice); + + return (TkFont *) fontPtr; +} + |