summaryrefslogtreecommitdiff
path: root/tk/mac/tkMacFont.c
diff options
context:
space:
mode:
Diffstat (limited to 'tk/mac/tkMacFont.c')
-rw-r--r--tk/mac/tkMacFont.c678
1 files changed, 678 insertions, 0 deletions
diff --git a/tk/mac/tkMacFont.c b/tk/mac/tkMacFont.c
new file mode 100644
index 00000000000..a23e47d1f84
--- /dev/null
+++ b/tk/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.
+ *
+ * RCS: @(#) $Id$
+ */
+
+#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;
+}
+