summaryrefslogtreecommitdiffstats
path: root/win/tkWinFont.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tkWinFont.c')
-rw-r--r--win/tkWinFont.c643
1 files changed, 643 insertions, 0 deletions
diff --git a/win/tkWinFont.c b/win/tkWinFont.c
new file mode 100644
index 0000000..c1d5161
--- /dev/null
+++ b/win/tkWinFont.c
@@ -0,0 +1,643 @@
+/*
+ * tkWinFont.c --
+ *
+ * Contains the Windows implementation of the platform-independant
+ * font package interface.
+ *
+ * Copyright (c) 1995-1997 Sun Microsystems, Inc.
+ * Copyright (c) 1994 Software Research Associates, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * SCCS: @(#) tkWinFont.c 1.20 97/05/14 15:45:30
+ */
+
+#include "tkWinInt.h"
+#include "tkFont.h"
+
+/*
+ * The following structure represents Windows' implementation of a font.
+ */
+
+typedef struct WinFont {
+ TkFont font; /* Stuff used by generic font package. Must
+ * be first in structure. */
+ HFONT hFont; /* Windows information about font. */
+ HWND hwnd; /* Toplevel window of application that owns
+ * this font, used for getting HDC. */
+ int widths[256]; /* Widths of first 256 chars in this font. */
+} WinFont;
+
+/*
+ * The following structure is used as to map between the Tcl strings
+ * that represent the system fonts and the numbers used by Windows.
+ */
+
+static TkStateMap systemMap[] = {
+ {ANSI_FIXED_FONT, "ansifixed"},
+ {ANSI_VAR_FONT, "ansi"},
+ {DEVICE_DEFAULT_FONT, "device"},
+ {OEM_FIXED_FONT, "oemfixed"},
+ {SYSTEM_FIXED_FONT, "systemfixed"},
+ {SYSTEM_FONT, "system"},
+ {-1, NULL}
+};
+
+#define ABS(x) (((x) < 0) ? -(x) : (x))
+
+static TkFont * AllocFont _ANSI_ARGS_((TkFont *tkFontPtr,
+ Tk_Window tkwin, HFONT hFont));
+static char * GetProperty _ANSI_ARGS_((CONST TkFontAttributes *faPtr,
+ CONST char *option));
+static int CALLBACK WinFontFamilyEnumProc _ANSI_ARGS_((ENUMLOGFONT *elfPtr,
+ NEWTEXTMETRIC *ntmPtr, int fontType,
+ LPARAM lParam));
+
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * 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 generic TkFont before calling TkpDeleteFont().
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+TkFont *
+TkpGetNativeFont(tkwin, name)
+ Tk_Window tkwin; /* For display where font will be used. */
+ CONST char *name; /* Platform-specific font name. */
+{
+ int object;
+ HFONT hFont;
+
+ object = TkFindStateNum(NULL, NULL, systemMap, name);
+ if (object < 0) {
+ return NULL;
+ }
+ hFont = GetStockObject(object);
+ if (hFont == NULL) {
+ panic("TkpGetNativeFont: can't allocate stock font");
+ }
+
+ return AllocFont(NULL, tkwin, hFont);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * 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. NULL is never returned.
+ *
+ * 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(tkFontPtr, tkwin, faPtr)
+ 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. */
+{
+ LOGFONT lf;
+ HFONT hFont;
+ Window window;
+ HWND hwnd;
+ HDC hdc;
+
+ window = Tk_WindowId(((TkWindow *) tkwin)->mainPtr->winPtr);
+ hwnd = (window == None) ? NULL : TkWinGetHWND(window);
+
+ hdc = GetDC(hwnd);
+ lf.lfHeight = -faPtr->pointsize;
+ if (lf.lfHeight < 0) {
+ lf.lfHeight = MulDiv(lf.lfHeight,
+ 254 * WidthOfScreen(Tk_Screen(tkwin)),
+ 720 * WidthMMOfScreen(Tk_Screen(tkwin)));
+ }
+ lf.lfWidth = 0;
+ lf.lfEscapement = 0;
+ lf.lfOrientation = 0;
+ lf.lfWeight = (faPtr->weight == TK_FW_NORMAL) ? FW_NORMAL : FW_BOLD;
+ lf.lfItalic = faPtr->slant;
+ lf.lfUnderline = faPtr->underline;
+ lf.lfStrikeOut = faPtr->overstrike;
+ lf.lfCharSet = DEFAULT_CHARSET;
+ lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfQuality = DEFAULT_QUALITY;
+ lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ if (faPtr->family == NULL) {
+ lf.lfFaceName[0] = '\0';
+ } else {
+ lstrcpyn(lf.lfFaceName, faPtr->family, sizeof(lf.lfFaceName));
+ }
+ ReleaseDC(hwnd, hdc);
+
+ /*
+ * Replace the standard X and Mac family names with the names that
+ * Windows likes.
+ */
+
+ if ((stricmp(lf.lfFaceName, "Times") == 0)
+ || (stricmp(lf.lfFaceName, "New York") == 0)) {
+ strcpy(lf.lfFaceName, "Times New Roman");
+ } else if ((stricmp(lf.lfFaceName, "Courier") == 0)
+ || (stricmp(lf.lfFaceName, "Monaco") == 0)) {
+ strcpy(lf.lfFaceName, "Courier New");
+ } else if ((stricmp(lf.lfFaceName, "Helvetica") == 0)
+ || (stricmp(lf.lfFaceName, "Geneva") == 0)) {
+ strcpy(lf.lfFaceName, "Arial");
+ }
+
+ hFont = CreateFontIndirect(&lf);
+ if (hFont == NULL) {
+ hFont = GetStockObject(SYSTEM_FONT);
+ if (hFont == NULL) {
+ panic("TkpGetFontFromAttributes: cannot get system font");
+ }
+ }
+ return AllocFont(tkFontPtr, tkwin, hFont);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * 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(tkFontPtr)
+ TkFont *tkFontPtr; /* Token of font to be deleted. */
+{
+ WinFont *fontPtr;
+
+ fontPtr = (WinFont *) tkFontPtr;
+ DeleteObject(fontPtr->hFont);
+ ckfree((char *) fontPtr);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TkpGetFontFamilies, WinFontEnumFamilyProc --
+ *
+ * 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(interp, tkwin)
+ Tcl_Interp *interp; /* Interp to hold result. */
+ Tk_Window tkwin; /* For display to query. */
+{
+ Window window;
+ HWND hwnd;
+ HDC hdc;
+
+ window = Tk_WindowId(tkwin);
+ hwnd = (window == (Window) NULL) ? NULL : TkWinGetHWND(window);
+
+ hdc = GetDC(hwnd);
+ EnumFontFamilies(hdc, NULL, (FONTENUMPROC) WinFontFamilyEnumProc,
+ (LPARAM) interp);
+ ReleaseDC(hwnd, hdc);
+}
+
+/* ARGSUSED */
+
+static int CALLBACK
+WinFontFamilyEnumProc(elfPtr, ntmPtr, fontType, lParam)
+ ENUMLOGFONT *elfPtr; /* Logical-font data. */
+ NEWTEXTMETRIC *ntmPtr; /* Physical-font data (not used). */
+ int fontType; /* Type of font (not used). */
+ LPARAM lParam; /* Interp to hold result. */
+{
+ Tcl_Interp *interp;
+
+ interp = (Tcl_Interp *) lParam;
+ Tcl_AppendElement(interp, elfPtr->elfLogFont.lfFaceName);
+ return 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(tkfont, source, numChars, maxLength, flags, lengthPtr)
+ 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. */
+{
+ WinFont *fontPtr;
+ HDC hdc;
+ HFONT hFont;
+ int curX, curIdx;
+
+ /*
+ * On the authority of the Gates Empire, Windows does not use kerning
+ * or fractional character widths when displaying text on the screen.
+ * So that means we can safely measure individual characters or spans
+ * of characters and add up the widths w/o any "off-by-one pixel"
+ * errors.
+ */
+
+ fontPtr = (WinFont *) tkfont;
+
+ hdc = GetDC(fontPtr->hwnd);
+ hFont = SelectObject(hdc, fontPtr->hFont);
+
+ if (numChars == 0) {
+ curX = 0;
+ curIdx = 0;
+ } else if (maxLength <= 0) {
+ SIZE size;
+
+ GetTextExtentPoint(hdc, source, numChars, &size);
+ curX = size.cx;
+ curIdx = numChars;
+ } else {
+ int newX, termX, sawNonSpace;
+ CONST char *term, *end, *p;
+ int ch;
+
+ ch = UCHAR(*source);
+ newX = curX = termX = 0;
+
+ term = source;
+ end = source + numChars;
+
+ sawNonSpace = !isspace(ch);
+ for (p = source; ; ) {
+ newX += fontPtr->widths[ch];
+ if (newX > maxLength) {
+ break;
+ }
+ curX = newX;
+ p++;
+ if (p >= end) {
+ term = end;
+ termX = curX;
+ break;
+ }
+
+ ch = UCHAR(*p);
+ if (isspace(ch)) {
+ if (sawNonSpace) {
+ term = p;
+ termX = curX;
+ sawNonSpace = 0;
+ }
+ } else {
+ sawNonSpace = 1;
+ }
+ }
+
+ /*
+ * P points to the first character that doesn't fit in the desired
+ * span. Use the flags to figure out what to return.
+ */
+
+ if ((flags & TK_PARTIAL_OK) && (p < end) && (curX < maxLength)) {
+ /*
+ * Include the first character that didn't quite fit in the desired
+ * span. The width returned will include the width of that extra
+ * character.
+ */
+
+ curX = newX;
+ p++;
+ }
+ if ((flags & TK_AT_LEAST_ONE) && (term == source) && (p < end)) {
+ term = p;
+ termX = curX;
+ if (term == source) {
+ term++;
+ termX = newX;
+ }
+ } else if ((p >= end) || !(flags & TK_WHOLE_WORDS)) {
+ term = p;
+ termX = curX;
+ }
+
+ curX = termX;
+ curIdx = term - source;
+ }
+
+ SelectObject(hdc, hFont);
+ ReleaseDC(fontPtr->hwnd, hdc);
+
+ *lengthPtr = curX;
+ 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, drawable, gc, tkfont, source, numChars, x, y)
+ 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, y; /* Coordinates at which to place origin of
+ * string when drawing. */
+{
+ HDC dc;
+ HFONT hFont;
+ TkWinDCState state;
+ WinFont *fontPtr;
+
+ fontPtr = (WinFont *) gc->font;
+ display->request++;
+
+ if (drawable == None) {
+ return;
+ }
+
+ dc = TkWinGetDrawableDC(display, drawable, &state);
+
+ SetROP2(dc, tkpWinRopModes[gc->function]);
+
+ if ((gc->fill_style == FillStippled
+ || gc->fill_style == FillOpaqueStippled)
+ && gc->stipple != None) {
+ TkWinDrawable *twdPtr = (TkWinDrawable *)gc->stipple;
+ HBRUSH oldBrush, stipple;
+ HBITMAP oldBitmap, bitmap;
+ HDC dcMem;
+ TEXTMETRIC tm;
+ SIZE size;
+
+ if (twdPtr->type != TWD_BITMAP) {
+ panic("unexpected drawable type in stipple");
+ }
+
+ /*
+ * Select stipple pattern into destination dc.
+ */
+
+ dcMem = CreateCompatibleDC(dc);
+
+ stipple = CreatePatternBrush(twdPtr->bitmap.handle);
+ SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL);
+ oldBrush = SelectObject(dc, stipple);
+
+ SetTextAlign(dcMem, TA_LEFT | TA_TOP);
+ SetTextColor(dcMem, gc->foreground);
+ SetBkMode(dcMem, TRANSPARENT);
+ SetBkColor(dcMem, RGB(0, 0, 0));
+
+ hFont = SelectObject(dcMem, fontPtr->hFont);
+
+ /*
+ * Compute the bounding box and create a compatible bitmap.
+ */
+
+ GetTextExtentPoint(dcMem, source, numChars, &size);
+ GetTextMetrics(dcMem, &tm);
+ size.cx -= tm.tmOverhang;
+ bitmap = CreateCompatibleBitmap(dc, size.cx, size.cy);
+ oldBitmap = SelectObject(dcMem, bitmap);
+
+ /*
+ * The following code is tricky because fonts are rendered in multiple
+ * colors. First we draw onto a black background and copy the white
+ * bits. Then we draw onto a white background and copy the black bits.
+ * Both the foreground and background bits of the font are ANDed with
+ * the stipple pattern as they are copied.
+ */
+
+ PatBlt(dcMem, 0, 0, size.cx, size.cy, BLACKNESS);
+ TextOut(dcMem, 0, 0, source, numChars);
+ BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem,
+ 0, 0, 0xEA02E9);
+ PatBlt(dcMem, 0, 0, size.cx, size.cy, WHITENESS);
+ TextOut(dcMem, 0, 0, source, numChars);
+ BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem,
+ 0, 0, 0x8A0E06);
+
+ /*
+ * Destroy the temporary bitmap and restore the device context.
+ */
+
+ SelectObject(dcMem, hFont);
+ SelectObject(dcMem, oldBitmap);
+ DeleteObject(bitmap);
+ DeleteDC(dcMem);
+ SelectObject(dc, oldBrush);
+ DeleteObject(stipple);
+ } else {
+ SetTextAlign(dc, TA_LEFT | TA_BASELINE);
+ SetTextColor(dc, gc->foreground);
+ SetBkMode(dc, TRANSPARENT);
+ hFont = SelectObject(dc, fontPtr->hFont);
+ TextOut(dc, x, y, source, numChars);
+ SelectObject(dc, hFont);
+ }
+ TkWinReleaseDrawableDC(drawable, dc, &state);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * AllocFont --
+ *
+ * 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 *
+AllocFont(tkFontPtr, tkwin, hFont)
+ 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. */
+ HFONT hFont; /* Windows information about font. */
+{
+ HWND hwnd;
+ WinFont *fontPtr;
+ HDC hdc;
+ TEXTMETRIC tm;
+ Window window;
+ char buf[LF_FACESIZE];
+ TkFontAttributes *faPtr;
+
+ if (tkFontPtr != NULL) {
+ fontPtr = (WinFont *) tkFontPtr;
+ DeleteObject(fontPtr->hFont);
+ } else {
+ fontPtr = (WinFont *) ckalloc(sizeof(WinFont));
+ }
+
+ window = Tk_WindowId(((TkWindow *) tkwin)->mainPtr->winPtr);
+ hwnd = (window == None) ? NULL : TkWinGetHWND(window);
+
+ hdc = GetDC(hwnd);
+ hFont = SelectObject(hdc, hFont);
+ GetTextFace(hdc, sizeof(buf), buf);
+ GetTextMetrics(hdc, &tm);
+ GetCharWidth(hdc, 0, 255, fontPtr->widths);
+
+ fontPtr->font.fid = (Font) fontPtr;
+
+ faPtr = &fontPtr->font.fa;
+ faPtr->family = Tk_GetUid(buf);
+ faPtr->pointsize = MulDiv(tm.tmHeight - tm.tmInternalLeading,
+ 720 * WidthMMOfScreen(Tk_Screen(tkwin)),
+ 254 * WidthOfScreen(Tk_Screen(tkwin)));
+ faPtr->weight = (tm.tmWeight > FW_MEDIUM) ? TK_FW_BOLD : TK_FW_NORMAL;
+ faPtr->slant = (tm.tmItalic != 0) ? TK_FS_ITALIC : TK_FS_ROMAN;
+ faPtr->underline = (tm.tmUnderlined != 0) ? 1 : 0;
+ faPtr->overstrike = (tm.tmStruckOut != 0) ? 1 : 0;
+
+ fontPtr->font.fm.ascent = tm.tmAscent;
+ fontPtr->font.fm.descent = tm.tmDescent;
+ fontPtr->font.fm.maxWidth = tm.tmMaxCharWidth;
+ fontPtr->font.fm.fixed = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
+
+ hFont = SelectObject(hdc, hFont);
+ ReleaseDC(hwnd, hdc);
+
+ fontPtr->hFont = hFont;
+ fontPtr->hwnd = hwnd;
+
+ return (TkFont *) fontPtr;
+}
+