Parent Directory | Revision Log | Patch
projs/trunk/shared_source/tk_base/tkwinfont.c revision 42 by dashley, Fri Oct 14 01:50:00 2016 UTC | projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkwinfont.c revision 71 by dashley, Sat Nov 5 11:07:06 2016 UTC | |
---|---|---|
# | Line 1 | Line 1 |
/* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tk_base/tkwinfont.c,v 1.1.1.1 2001/06/13 05:13:30 dtashley Exp $ */ | ||
/* | ||
* tkWinFont.c -- | ||
* | ||
* Contains the Windows implementation of the platform-independant | ||
* font package interface. | ||
* | ||
* Copyright (c) 1994 Software Research Associates, Inc. | ||
* Copyright (c) 1995-1997 Sun Microsystems, Inc. | ||
* Copyright (c) 1998-1999 by Scriptics Corporation. | ||
* | ||
* See the file "license.terms" for information on usage and redistribution | ||
* of this file, and for a DISCLAIMER OF ALL WARRANTIES. | ||
* | ||
* RCS: @(#) $Id: tkwinfont.c,v 1.1.1.1 2001/06/13 05:13:30 dtashley Exp $ | ||
*/ | ||
#include "tkWinInt.h" | ||
#include "tkFont.h" | ||
/* | ||
* 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 Windows, a "font family" is uniquely identified by its face name. | ||
*/ | ||
#define FONTMAP_SHIFT 10 | ||
#define FONTMAP_PAGES (1 << (sizeof(Tcl_UniChar)*8 - FONTMAP_SHIFT)) | ||
#define FONTMAP_BITSPERPAGE (1 << FONTMAP_SHIFT) | ||
typedef struct 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. | ||
*/ | ||
Tk_Uid faceName; /* Face name key for this FontFamily. */ | ||
/* | ||
* Derived properties. | ||
*/ | ||
Tcl_Encoding encoding; /* Encoding for this font family. */ | ||
int isSymbolFont; /* Non-zero if this is a symbol font. */ | ||
int isWideFont; /* 1 if this is a double-byte font, 0 | ||
* otherwise. */ | ||
BOOL (WINAPI *textOutProc)(HDC, int, int, TCHAR *, int); | ||
/* The procedure to use to draw text after | ||
* it has been converted from UTF-8 to the | ||
* encoding of this font. */ | ||
BOOL (WINAPI *getTextExtentPoint32Proc)(HDC, TCHAR *, int, LPSIZE); | ||
/* The procedure to use to measure text after | ||
* it has been converted from UTF-8 to the | ||
* encoding of this font. */ | ||
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. */ | ||
/* | ||
* Cached Truetype font info. | ||
*/ | ||
int segCount; /* The length of the following arrays. */ | ||
USHORT *startCount; /* Truetype information about the font, */ | ||
USHORT *endCount; /* indicating which characters this font | ||
* can display (malloced). The format of | ||
* this information is (relatively) compact, | ||
* but would take longer to search than | ||
* indexing into the fontMap[][] table. */ | ||
} 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. | ||
*/ | ||
typedef struct SubFont { | ||
char **fontMap; /* Pointer to font map from the FontFamily, | ||
* cached here to save a dereference. */ | ||
HFONT hFont; /* The specific screen font that will be | ||
* used when displaying/measuring chars | ||
* belonging to the FontFamily. */ | ||
FontFamily *familyPtr; /* The FontFamily for this SubFont. */ | ||
} SubFont; | ||
/* | ||
* The following structure represents Windows' implementation of a font | ||
* object. | ||
*/ | ||
#define SUBFONT_SPACE 3 | ||
#define BASE_CHARS 128 | ||
typedef struct WinFont { | ||
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. */ | ||
HWND hwnd; /* Toplevel window of application that owns | ||
* this font, used for getting HDC for | ||
* offscreen measurements. */ | ||
int pixelSize; /* Original pixel size used when font was | ||
* constructed. */ | ||
int widths[BASE_CHARS]; /* Widths of first 128 chars in the base | ||
* font, for handling common case. The base | ||
* font is always used to draw characters | ||
* between 0x0000 and 0x007f. */ | ||
} WinFont; | ||
/* | ||
* The following structure is passed as the LPARAM when calling the font | ||
* enumeration procedure to determine if a font can support the given | ||
* character. | ||
*/ | ||
typedef struct CanUse { | ||
HDC hdc; | ||
WinFont *fontPtr; | ||
Tcl_DString *nameTriedPtr; | ||
int ch; | ||
SubFont *subFontPtr; | ||
} CanUse; | ||
/* | ||
* The following structure is used 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} | ||
}; | ||
typedef struct ThreadSpecificData { | ||
FontFamily *fontFamilyList; /* 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. */ | ||
Tcl_HashTable uidTable; | ||
} ThreadSpecificData; | ||
static Tcl_ThreadDataKey dataKey; | ||
/* | ||
* Information cached about the system at startup time. | ||
*/ | ||
static Tcl_Encoding unicodeEncoding; | ||
static Tcl_Encoding systemEncoding; | ||
/* | ||
* Procedures used only in this file. | ||
*/ | ||
static FontFamily * AllocFontFamily(HDC hdc, HFONT hFont, int base); | ||
static SubFont * CanUseFallback(HDC hdc, WinFont *fontPtr, | ||
char *fallbackName, int ch); | ||
static SubFont * CanUseFallbackWithAliases(HDC hdc, WinFont *fontPtr, | ||
char *faceName, int ch, Tcl_DString *nameTriedPtr); | ||
static int FamilyExists(HDC hdc, CONST char *faceName); | ||
static char * FamilyOrAliasExists(HDC hdc, CONST char *faceName); | ||
static SubFont * FindSubFontForChar(WinFont *fontPtr, int ch); | ||
static void FontMapInsert(SubFont *subFontPtr, int ch); | ||
static void FontMapLoadPage(SubFont *subFontPtr, int row); | ||
static int FontMapLookup(SubFont *subFontPtr, int ch); | ||
static void FreeFontFamily(FontFamily *familyPtr); | ||
static HFONT GetScreenFont(CONST TkFontAttributes *faPtr, | ||
CONST char *faceName, int pixelSize); | ||
static void InitFont(Tk_Window tkwin, HFONT hFont, | ||
int overstrike, WinFont *tkFontPtr); | ||
static void InitSubFont(HDC hdc, HFONT hFont, int base, | ||
SubFont *subFontPtr); | ||
static int LoadFontRanges(HDC hdc, HFONT hFont, | ||
USHORT **startCount, USHORT **endCount, | ||
int *symbolPtr); | ||
static void MultiFontTextOut(HDC hdc, WinFont *fontPtr, | ||
CONST char *source, int numBytes, int x, int y); | ||
static void ReleaseFont(WinFont *fontPtr); | ||
static void ReleaseSubFont(SubFont *subFontPtr); | ||
static int SeenName(CONST char *name, Tcl_DString *dsPtr); | ||
static void SwapLong(PULONG p); | ||
static void SwapShort(USHORT *p); | ||
static int CALLBACK WinFontCanUseProc(ENUMLOGFONT *lfPtr, | ||
NEWTEXTMETRIC *tmPtr, int fontType, | ||
LPARAM lParam); | ||
static int CALLBACK WinFontExistProc(ENUMLOGFONT *lfPtr, | ||
NEWTEXTMETRIC *tmPtr, int fontType, | ||
LPARAM lParam); | ||
static int CALLBACK WinFontFamilyEnumProc(ENUMLOGFONT *lfPtr, | ||
NEWTEXTMETRIC *tmPtr, int fontType, | ||
LPARAM lParam); | ||
/* | ||
*------------------------------------------------------------------------- | ||
* | ||
* TkpFontPkgInit -- | ||
* | ||
* This procedure is called when an application is created. It | ||
* initializes all the structures that are used by the | ||
* platform-dependent code on a per application basis. | ||
* | ||
* Results: | ||
* None. | ||
* | ||
* Side effects: | ||
* | ||
* None. | ||
* | ||
*------------------------------------------------------------------------- | ||
*/ | ||
void | ||
TkpFontPkgInit( | ||
TkMainInfo *mainPtr) /* The application being created. */ | ||
{ | ||
unicodeEncoding = Tcl_GetEncoding(NULL, "unicode"); | ||
if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { | ||
/* | ||
* If running NT, then we will be calling some Unicode functions | ||
* explictly. So, even if the Tcl system encoding isn't Unicode, | ||
* make sure we convert to/from the Unicode char set. | ||
*/ | ||
systemEncoding = unicodeEncoding; | ||
} | ||
} | ||
/* | ||
*--------------------------------------------------------------------------- | ||
* | ||
* 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: | ||
* Memory allocated. | ||
* | ||
*--------------------------------------------------------------------------- | ||
*/ | ||
TkFont * | ||
TkpGetNativeFont( | ||
Tk_Window tkwin, /* For display where font will be used. */ | ||
CONST char *name) /* Platform-specific font name. */ | ||
{ | ||
int object; | ||
WinFont *fontPtr; | ||
object = TkFindStateNum(NULL, NULL, systemMap, name); | ||
if (object < 0) { | ||
return NULL; | ||
} | ||
tkwin = (Tk_Window) ((TkWindow *) tkwin)->mainPtr->winPtr; | ||
fontPtr = (WinFont *) ckalloc(sizeof(WinFont)); | ||
InitFont(tkwin, GetStockObject(object), 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. 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: | ||
* Memory allocated. | ||
* | ||
*--------------------------------------------------------------------------- | ||
*/ | ||
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. */ | ||
{ | ||
int i, j; | ||
HDC hdc; | ||
HWND hwnd; | ||
HFONT hFont; | ||
Window window; | ||
WinFont *fontPtr; | ||
char ***fontFallbacks; | ||
char *faceName, *fallback, *actualName; | ||
tkwin = (Tk_Window) ((TkWindow *) tkwin)->mainPtr->winPtr; | ||
window = Tk_WindowId(tkwin); | ||
hwnd = (window == None) ? NULL : TkWinGetHWND(window); | ||
hdc = GetDC(hwnd); | ||
/* | ||
* Algorithm to get the closest font name to the one requested. | ||
* | ||
* try fontname | ||
* try all aliases for fontname | ||
* foreach fallback for fontname | ||
* try the fallback | ||
* try all aliases for the fallback | ||
*/ | ||
faceName = faPtr->family; | ||
if (faceName != NULL) { | ||
actualName = FamilyOrAliasExists(hdc, faceName); | ||
if (actualName != NULL) { | ||
faceName = actualName; | ||
goto found; | ||
} | ||
fontFallbacks = TkFontGetFallbacks(); | ||
for (i = 0; fontFallbacks[i] != NULL; i++) { | ||
for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) { | ||
if (strcasecmp(faceName, fallback) == 0) { | ||
break; | ||
} | ||
} | ||
if (fallback != NULL) { | ||
for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) { | ||
actualName = FamilyOrAliasExists(hdc, fallback); | ||
if (actualName != NULL) { | ||
faceName = actualName; | ||
goto found; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
found: | ||
ReleaseDC(hwnd, hdc); | ||
hFont = GetScreenFont(faPtr, faceName, TkFontGetPixels(tkwin, faPtr->size)); | ||
if (tkFontPtr == NULL) { | ||
fontPtr = (WinFont *) ckalloc(sizeof(WinFont)); | ||
} else { | ||
fontPtr = (WinFont *) tkFontPtr; | ||
ReleaseFont(fontPtr); | ||
} | ||
InitFont(tkwin, hFont, faPtr->overstrike, 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. | ||
* | ||
*--------------------------------------------------------------------------- | ||
*/ | ||
void | ||
TkpDeleteFont( | ||
TkFont *tkFontPtr) /* Token of font to be deleted. */ | ||
{ | ||
WinFont *fontPtr; | ||
fontPtr = (WinFont *) tkFontPtr; | ||
ReleaseFont(fontPtr); | ||
} | ||
/* | ||
*--------------------------------------------------------------------------- | ||
* | ||
* TkpGetFontFamilies, WinFontFamilyEnumProc -- | ||
* | ||
* 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. | ||
* | ||
*--------------------------------------------------------------------------- | ||
*/ | ||
void | ||
TkpGetFontFamilies( | ||
Tcl_Interp *interp, /* Interp to hold result. */ | ||
Tk_Window tkwin) /* For display to query. */ | ||
{ | ||
HDC hdc; | ||
HWND hwnd; | ||
Window window; | ||
window = Tk_WindowId(tkwin); | ||
hwnd = (window == None) ? NULL : TkWinGetHWND(window); | ||
hdc = GetDC(hwnd); | ||
/* | ||
* On any version NT, there may fonts with international names. | ||
* Use the NT-only Unicode version of EnumFontFamilies to get the | ||
* font names. If we used the ANSI version on a non-internationalized | ||
* version of NT, we would get font names with '?' replacing all | ||
* the international characters. | ||
* | ||
* On a non-internationalized verson of 95, fonts with international | ||
* names are not allowed, so the ANSI version of EnumFontFamilies will | ||
* work. On an internationalized version of 95, there may be fonts with | ||
* international names; the ANSI version will work, fetching the | ||
* name in the system code page. Can't use the Unicode version of | ||
* EnumFontFamilies because it only exists under NT. | ||
*/ | ||
if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { | ||
EnumFontFamiliesW(hdc, NULL, (FONTENUMPROCW) WinFontFamilyEnumProc, | ||
(LPARAM) interp); | ||
} else { | ||
EnumFontFamiliesA(hdc, NULL, (FONTENUMPROCA) WinFontFamilyEnumProc, | ||
(LPARAM) interp); | ||
} | ||
ReleaseDC(hwnd, hdc); | ||
} | ||
static int CALLBACK | ||
WinFontFamilyEnumProc( | ||
ENUMLOGFONT *lfPtr, /* Logical-font data. */ | ||
NEWTEXTMETRIC *tmPtr, /* Physical-font data (not used). */ | ||
int fontType, /* Type of font (not used). */ | ||
LPARAM lParam) /* Result object to hold result. */ | ||
{ | ||
char *faceName; | ||
Tcl_DString faceString; | ||
Tcl_Obj *strPtr; | ||
Tcl_Interp *interp; | ||
interp = (Tcl_Interp *) lParam; | ||
faceName = lfPtr->elfLogFont.lfFaceName; | ||
Tcl_ExternalToUtfDString(systemEncoding, faceName, -1, &faceString); | ||
strPtr = Tcl_NewStringObj(Tcl_DStringValue(&faceString), | ||
Tcl_DStringLength(&faceString)); | ||
Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), strPtr); | ||
Tcl_DStringFree(&faceString); | ||
return 1; | ||
} | ||
/* | ||
*------------------------------------------------------------------------- | ||
* | ||
* 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. | ||
* | ||
*------------------------------------------------------------------------- | ||
*/ | ||
void | ||
TkpGetSubFonts( | ||
Tcl_Interp *interp, /* Interp to hold result. */ | ||
Tk_Font tkfont) /* Font object to query. */ | ||
{ | ||
int i; | ||
WinFont *fontPtr; | ||
FontFamily *familyPtr; | ||
Tcl_Obj *resultPtr, *strPtr; | ||
resultPtr = Tcl_GetObjResult(interp); | ||
fontPtr = (WinFont *) tkfont; | ||
for (i = 0; i < fontPtr->numSubFonts; i++) { | ||
familyPtr = fontPtr->subFontArray[i].familyPtr; | ||
strPtr = Tcl_NewStringObj(familyPtr->faceName, -1); | ||
Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); | ||
} | ||
} | ||
/* | ||
*--------------------------------------------------------------------------- | ||
* | ||
* Tk_MeasureChars -- | ||
* | ||
* Determine the number of bytes 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. | ||
* | ||
*--------------------------------------------------------------------------- | ||
*/ | ||
int | ||
Tk_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 in pixels; 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. */ | ||
{ | ||
HDC hdc; | ||
HFONT oldFont; | ||
WinFont *fontPtr; | ||
int curX, curByte; | ||
SubFont *lastSubFontPtr; | ||
/* | ||
* According to Microsoft tech support, 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); | ||
lastSubFontPtr = &fontPtr->subFontArray[0]; | ||
oldFont = SelectObject(hdc, lastSubFontPtr->hFont); | ||
if (numBytes == 0) { | ||
curX = 0; | ||
curByte = 0; | ||
} else if (maxLength < 0) { | ||
Tcl_UniChar ch; | ||
SIZE size; | ||
FontFamily *familyPtr; | ||
Tcl_DString runString; | ||
SubFont *thisSubFontPtr; | ||
CONST char *p, *end, *next; | ||
/* | ||
* 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); | ||
thisSubFontPtr = FindSubFontForChar(fontPtr, ch); | ||
if (thisSubFontPtr != lastSubFontPtr) { | ||
familyPtr = lastSubFontPtr->familyPtr; | ||
Tcl_UtfToExternalDString(familyPtr->encoding, source, | ||
p - source, &runString); | ||
(*familyPtr->getTextExtentPoint32Proc)(hdc, | ||
Tcl_DStringValue(&runString), | ||
Tcl_DStringLength(&runString) >> familyPtr->isWideFont, | ||
&size); | ||
curX += size.cx; | ||
Tcl_DStringFree(&runString); | ||
lastSubFontPtr = thisSubFontPtr; | ||
source = p; | ||
SelectObject(hdc, lastSubFontPtr->hFont); | ||
} | ||
p = next; | ||
} | ||
familyPtr = lastSubFontPtr->familyPtr; | ||
Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source, | ||
&runString); | ||
(*familyPtr->getTextExtentPoint32Proc)(hdc, | ||
Tcl_DStringValue(&runString), | ||
Tcl_DStringLength(&runString) >> familyPtr->isWideFont, | ||
&size); | ||
curX += size.cx; | ||
Tcl_DStringFree(&runString); | ||
curByte = numBytes; | ||
} else { | ||
Tcl_UniChar ch; | ||
SIZE size; | ||
char buf[16]; | ||
FontFamily *familyPtr; | ||
SubFont *thisSubFontPtr; | ||
CONST char *term, *end, *p, *next; | ||
int newX, termX, sawNonSpace, dstWrote; | ||
/* | ||
* How many chars will fit in the space allotted? | ||
* This first version may be inefficient because it measures | ||
* every character individually. There is a function call that | ||
* can measure multiple characters at once and return the | ||
* offset of each of them, but it only works on NT, even though | ||
* the documentation claims it works for 95. | ||
* TODO: verify that GetTextExtentExPoint is still broken in '95, and | ||
* possibly use it for NT anyway since it should be much faster and | ||
* more accurate. | ||
*/ | ||
next = source + Tcl_UtfToUniChar(source, &ch); | ||
newX = curX = termX = 0; | ||
term = source; | ||
end = source + numBytes; | ||
sawNonSpace = (ch > 255) || !isspace(ch); | ||
for (p = source; ; ) { | ||
if (ch < BASE_CHARS) { | ||
newX += fontPtr->widths[ch]; | ||
} else { | ||
thisSubFontPtr = FindSubFontForChar(fontPtr, ch); | ||
if (thisSubFontPtr != lastSubFontPtr) { | ||
SelectObject(hdc, thisSubFontPtr->hFont); | ||
lastSubFontPtr = thisSubFontPtr; | ||
} | ||
familyPtr = lastSubFontPtr->familyPtr; | ||
Tcl_UtfToExternal(NULL, familyPtr->encoding, p, next - p, | ||
0, NULL, buf, sizeof(buf), NULL, &dstWrote, NULL); | ||
(*familyPtr->getTextExtentPoint32Proc)(hdc, buf, | ||
dstWrote >> familyPtr->isWideFont, &size); | ||
newX += size.cx; | ||
} | ||
if (newX > maxLength) { | ||
break; | ||
} | ||
curX = newX; | ||
p = next; | ||
if (p >= end) { | ||
term = end; | ||
termX = curX; | ||
break; | ||
} | ||
next += Tcl_UtfToUniChar(next, &ch); | ||
if ((ch < 256) && 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 += Tcl_UtfToUniChar(p, &ch); | ||
} | ||
if ((flags & TK_AT_LEAST_ONE) && (term == source) && (p < end)) { | ||
term = p; | ||
termX = curX; | ||
if (term == source) { | ||
term += Tcl_UtfToUniChar(term, &ch); | ||
termX = newX; | ||
} | ||
} else if ((p >= end) || !(flags & TK_WHOLE_WORDS)) { | ||
term = p; | ||
termX = curX; | ||
} | ||
curX = termX; | ||
curByte = term - source; | ||
} | ||
SelectObject(hdc, oldFont); | ||
ReleaseDC(fontPtr->hwnd, hdc); | ||
*lengthPtr = curX; | ||
return curByte; | ||
} | ||
/* | ||
*--------------------------------------------------------------------------- | ||
* | ||
* 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, /* 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. */ | ||
{ | ||
HDC dc; | ||
WinFont *fontPtr; | ||
TkWinDCState state; | ||
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_BASELINE); | ||
SetTextColor(dcMem, gc->foreground); | ||
SetBkMode(dcMem, TRANSPARENT); | ||
SetBkColor(dcMem, RGB(0, 0, 0)); | ||
/* | ||
* Compute the bounding box and create a compatible bitmap. | ||
*/ | ||
GetTextExtentPoint(dcMem, source, numBytes, &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); | ||
MultiFontTextOut(dc, fontPtr, source, numBytes, x, y); | ||
BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem, | ||
0, 0, 0xEA02E9); | ||
PatBlt(dcMem, 0, 0, size.cx, size.cy, WHITENESS); | ||
MultiFontTextOut(dc, fontPtr, source, numBytes, x, y); | ||
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, oldBitmap); | ||
DeleteObject(bitmap); | ||
DeleteDC(dcMem); | ||
SelectObject(dc, oldBrush); | ||
DeleteObject(stipple); | ||
} else { | ||
SetTextAlign(dc, TA_LEFT | TA_BASELINE); | ||
SetTextColor(dc, gc->foreground); | ||
SetBkMode(dc, TRANSPARENT); | ||
MultiFontTextOut(dc, fontPtr, source, numBytes, x, y); | ||
} | ||
TkWinReleaseDrawableDC(drawable, dc, &state); | ||
} | ||
/* | ||
*------------------------------------------------------------------------- | ||
* | ||
* MultiFontTextOut -- | ||
* | ||
* 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 void | ||
MultiFontTextOut( | ||
HDC hdc, /* HDC to draw into. */ | ||
WinFont *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. */ | ||
{ | ||
Tcl_UniChar ch; | ||
SIZE size; | ||
HFONT oldFont; | ||
FontFamily *familyPtr; | ||
Tcl_DString runString; | ||
CONST char *p, *end, *next; | ||
SubFont *lastSubFontPtr, *thisSubFontPtr; | ||
lastSubFontPtr = &fontPtr->subFontArray[0]; | ||
oldFont = SelectObject(hdc, lastSubFontPtr->hFont); | ||
end = source + numBytes; | ||
for (p = source; p < end; ) { | ||
next = p + Tcl_UtfToUniChar(p, &ch); | ||
thisSubFontPtr = FindSubFontForChar(fontPtr, ch); | ||
if (thisSubFontPtr != lastSubFontPtr) { | ||
if (p > source) { | ||
familyPtr = lastSubFontPtr->familyPtr; | ||
Tcl_UtfToExternalDString(familyPtr->encoding, source, | ||
p - source, &runString); | ||
(*familyPtr->textOutProc)(hdc, x, y, | ||
Tcl_DStringValue(&runString), | ||
Tcl_DStringLength(&runString) >> familyPtr->isWideFont); | ||
(*familyPtr->getTextExtentPoint32Proc)(hdc, | ||
Tcl_DStringValue(&runString), | ||
Tcl_DStringLength(&runString) >> familyPtr->isWideFont, | ||
&size); | ||
x += size.cx; | ||
Tcl_DStringFree(&runString); | ||
} | ||
lastSubFontPtr = thisSubFontPtr; | ||
source = p; | ||
SelectObject(hdc, lastSubFontPtr->hFont); | ||
} | ||
p = next; | ||
} | ||
if (p > source) { | ||
familyPtr = lastSubFontPtr->familyPtr; | ||
Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source, | ||
&runString); | ||
(*familyPtr->textOutProc)(hdc, x, y, Tcl_DStringValue(&runString), | ||
Tcl_DStringLength(&runString) >> familyPtr->isWideFont); | ||
Tcl_DStringFree(&runString); | ||
} | ||
SelectObject(hdc, oldFont); | ||
} | ||
/* | ||
*--------------------------------------------------------------------------- | ||
* | ||
* InitFont -- | ||
* | ||
* Helper for TkpGetNativeFont() and TkpGetFontFromAttributes(). | ||
* Initializes the memory for a new WinFont that wraps the | ||
* platform-specific data. | ||
* | ||
* The caller is responsible for initializing the fields of the | ||
* WinFont that are used exclusively by the generic TkFont code, and | ||
* for releasing those fields before calling TkpDeleteFont(). | ||
* | ||
* Results: | ||
* Fills the WinFont structure. | ||
* | ||
* Side effects: | ||
* Memory allocated. | ||
* | ||
*--------------------------------------------------------------------------- | ||
*/ | ||
static void | ||
InitFont( | ||
Tk_Window tkwin, /* Main window of interp in which font will | ||
* be used, for getting HDC. */ | ||
HFONT hFont, /* Windows token for font. */ | ||
int overstrike, /* The overstrike attribute of logfont used | ||
* to allocate this font. For some reason, | ||
* the TEXTMETRICs may contain incorrect info | ||
* in the tmStruckOut field. */ | ||
WinFont *fontPtr) /* Filled with information constructed from | ||
* the above arguments. */ | ||
{ | ||
HDC hdc; | ||
HWND hwnd; | ||
HFONT oldFont; | ||
TEXTMETRIC tm; | ||
Window window; | ||
TkFontMetrics *fmPtr; | ||
Tcl_Encoding encoding; | ||
Tcl_DString faceString; | ||
TkFontAttributes *faPtr; | ||
char buf[LF_FACESIZE * sizeof(WCHAR)]; | ||
window = Tk_WindowId(tkwin); | ||
hwnd = (window == None) ? NULL : TkWinGetHWND(window); | ||
hdc = GetDC(hwnd); | ||
oldFont = SelectObject(hdc, hFont); | ||
GetTextMetrics(hdc, &tm); | ||
/* | ||
* On any version NT, there may fonts with international names. | ||
* Use the NT-only Unicode version of GetTextFace to get the font's | ||
* name. If we used the ANSI version on a non-internationalized | ||
* version of NT, we would get a font name with '?' replacing all | ||
* the international characters. | ||
* | ||
* On a non-internationalized verson of 95, fonts with international | ||
* names are not allowed, so the ANSI version of GetTextFace will work. | ||
* On an internationalized version of 95, there may be fonts with | ||
* international names; the ANSI version will work, fetching the | ||
* name in the international system code page. Can't use the Unicode | ||
* version of GetTextFace because it only exists under NT. | ||
*/ | ||
if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { | ||
GetTextFaceW(hdc, LF_FACESIZE, (WCHAR *) buf); | ||
} else { | ||
GetTextFaceA(hdc, LF_FACESIZE, (char *) buf); | ||
} | ||
Tcl_ExternalToUtfDString(systemEncoding, buf, -1, &faceString); | ||
fontPtr->font.fid = (Font) fontPtr; | ||
faPtr = &fontPtr->font.fa; | ||
faPtr->family = Tk_GetUid(Tcl_DStringValue(&faceString)); | ||
faPtr->size = TkFontGetPoints(tkwin, -(tm.tmHeight - tm.tmInternalLeading)); | ||
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 = overstrike; | ||
fmPtr = &fontPtr->font.fm; | ||
fmPtr->ascent = tm.tmAscent; | ||
fmPtr->descent = tm.tmDescent; | ||
fmPtr->maxWidth = tm.tmMaxCharWidth; | ||
fmPtr->fixed = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH); | ||
fontPtr->hwnd = hwnd; | ||
fontPtr->pixelSize = tm.tmHeight - tm.tmInternalLeading; | ||
fontPtr->numSubFonts = 1; | ||
fontPtr->subFontArray = fontPtr->staticSubFonts; | ||
InitSubFont(hdc, hFont, 1, &fontPtr->subFontArray[0]); | ||
encoding = fontPtr->subFontArray[0].familyPtr->encoding; | ||
if (encoding == unicodeEncoding) { | ||
GetCharWidthW(hdc, 0, BASE_CHARS - 1, fontPtr->widths); | ||
} else { | ||
GetCharWidthA(hdc, 0, BASE_CHARS - 1, fontPtr->widths); | ||
} | ||
Tcl_DStringFree(&faceString); | ||
SelectObject(hdc, oldFont); | ||
ReleaseDC(hwnd, hdc); | ||
} | ||
/* | ||
*------------------------------------------------------------------------- | ||
* | ||
* ReleaseFont -- | ||
* | ||
* Called to release the windows-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 void | ||
ReleaseFont( | ||
WinFont *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 void | ||
InitSubFont( | ||
HDC hdc, /* HDC in which font can be selected. */ | ||
HFONT hFont, /* The screen font. */ | ||
int base, /* Non-zero if this SubFont is being used | ||
* as the base font for a font object. */ | ||
SubFont *subFontPtr) /* Filled with SubFont constructed from | ||
* above attributes. */ | ||
{ | ||
subFontPtr->hFont = hFont; | ||
subFontPtr->familyPtr = AllocFontFamily(hdc, hFont, base); | ||
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 void | ||
ReleaseSubFont( | ||
SubFont *subFontPtr) /* The SubFont to delete. */ | ||
{ | ||
DeleteObject(subFontPtr->hFont); | ||
FreeFontFamily(subFontPtr->familyPtr); | ||
} | ||
/* | ||
*------------------------------------------------------------------------- | ||
* | ||
* AllocFontFamily -- | ||
* | ||
* Find the FontFamily structure associated with the given font | ||
* name. The information should be stored by the caller in a | ||
* SubFont and used when determining if that SubFont supports a | ||
* character. | ||
* | ||
* Cannot use the string name used to construct the font as the | ||
* key, because the capitalization may not be canonical. Therefore | ||
* use the face name actually retrieved from the font metrics as | ||
* the key. | ||
* | ||
* 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. TrueType character existence metrics are | ||
* loaded into the FontFamily structure. | ||
* | ||
*------------------------------------------------------------------------- | ||
*/ | ||
static FontFamily * | ||
AllocFontFamily( | ||
HDC hdc, /* HDC in which font can be selected. */ | ||
HFONT hFont, /* Screen font whose FontFamily is to be | ||
* returned. */ | ||
int base) /* Non-zero if this font family is to be | ||
* used in the base font of a font object. */ | ||
{ | ||
Tk_Uid faceName; | ||
FontFamily *familyPtr; | ||
Tcl_DString faceString; | ||
Tcl_Encoding encoding; | ||
char buf[LF_FACESIZE * sizeof(WCHAR)]; | ||
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) | ||
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); | ||
hFont = SelectObject(hdc, hFont); | ||
if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { | ||
GetTextFaceW(hdc, LF_FACESIZE, (WCHAR *) buf); | ||
} else { | ||
GetTextFaceA(hdc, LF_FACESIZE, (char *) buf); | ||
} | ||
Tcl_ExternalToUtfDString(systemEncoding, buf, -1, &faceString); | ||
faceName = Tk_GetUid(Tcl_DStringValue(&faceString)); | ||
Tcl_DStringFree(&faceString); | ||
hFont = SelectObject(hdc, hFont); | ||
familyPtr = tsdPtr->fontFamilyList; | ||
for ( ; familyPtr != NULL; familyPtr = familyPtr->nextPtr) { | ||
if (familyPtr->faceName == faceName) { | ||
familyPtr->refCount++; | ||
return familyPtr; | ||
} | ||
} | ||
familyPtr = (FontFamily *) ckalloc(sizeof(FontFamily)); | ||
memset(familyPtr, 0, sizeof(FontFamily)); | ||
familyPtr->nextPtr = tsdPtr->fontFamilyList; | ||
tsdPtr->fontFamilyList = familyPtr; | ||
/* | ||
* Set key for this FontFamily. | ||
*/ | ||
familyPtr->faceName = faceName; | ||
/* | ||
* 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->segCount = LoadFontRanges(hdc, hFont, &familyPtr->startCount, | ||
&familyPtr->endCount, &familyPtr->isSymbolFont); | ||
encoding = NULL; | ||
if (familyPtr->isSymbolFont != 0) { | ||
/* | ||
* Symbol fonts are handled specially. For instance, Unicode 0393 | ||
* (GREEK CAPITAL GAMMA) must be mapped to Symbol character 0047 | ||
* (GREEK CAPITAL GAMMA), because the Symbol font doesn't have a | ||
* GREEK CAPITAL GAMMA at location 0393. If Tk interpreted the | ||
* Symbol font using the Unicode encoding, it would decide that | ||
* the Symbol font has no GREEK CAPITAL GAMMA, because the Symbol | ||
* encoding (of course) reports that character 0393 doesn't exist. | ||
* | ||
* With non-symbol Windows fonts, such as Times New Roman, if the | ||
* font has a GREEK CAPITAL GAMMA, it will be found in the correct | ||
* Unicode location (0393); the GREEK CAPITAL GAMMA will not be off | ||
* hiding at some other location. | ||
*/ | ||
encoding = Tcl_GetEncoding(NULL, faceName); | ||
} | ||
if (encoding == NULL) { | ||
encoding = Tcl_GetEncoding(NULL, "unicode"); | ||
familyPtr->textOutProc = | ||
(BOOL (WINAPI *)(HDC, int, int, TCHAR *, int)) TextOutW; | ||
familyPtr->getTextExtentPoint32Proc = | ||
(BOOL (WINAPI *)(HDC, TCHAR *, int, LPSIZE)) GetTextExtentPoint32W; | ||
familyPtr->isWideFont = 1; | ||
} else { | ||
familyPtr->textOutProc = | ||
(BOOL (WINAPI *)(HDC, int, int, TCHAR *, int)) TextOutA; | ||
familyPtr->getTextExtentPoint32Proc = | ||
(BOOL (WINAPI *)(HDC, TCHAR *, int, LPSIZE)) GetTextExtentPoint32A; | ||
familyPtr->isWideFont = 0; | ||
} | ||
familyPtr->encoding = encoding; | ||
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 void | ||
FreeFontFamily( | ||
FontFamily *familyPtr) /* The FontFamily to delete. */ | ||
{ | ||
int i; | ||
FontFamily **familyPtrPtr; | ||
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) | ||
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); | ||
if (familyPtr == NULL) { | ||
return; | ||
} | ||
familyPtr->refCount--; | ||
if (familyPtr->refCount > 0) { | ||
return; | ||
} | ||
for (i = 0; i < FONTMAP_PAGES; i++) { | ||
if (familyPtr->fontMap[i] != NULL) { | ||
ckfree(familyPtr->fontMap[i]); | ||
} | ||
} | ||
if (familyPtr->startCount != NULL) { | ||
ckfree((char *) familyPtr->startCount); | ||
} | ||
if (familyPtr->endCount != NULL) { | ||
ckfree((char *) familyPtr->endCount); | ||
} | ||
if (familyPtr->encoding != unicodeEncoding) { | ||
Tcl_FreeEncoding(familyPtr->encoding); | ||
} | ||
/* | ||
* Delete from list. | ||
*/ | ||
for (familyPtrPtr = &tsdPtr->fontFamilyList; ; ) { | ||
if (*familyPtrPtr == familyPtr) { | ||
*familyPtrPtr = familyPtr->nextPtr; | ||
break; | ||
} | ||
familyPtrPtr = &(*familyPtrPtr)->nextPtr; | ||
} | ||
ckfree((char *) familyPtr); | ||
} | ||
/* | ||
*------------------------------------------------------------------------- | ||
* | ||
* FindSubFontForChar -- | ||
* | ||
* Determine which 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( | ||
WinFont *fontPtr, /* The font object with which the character | ||
* will be displayed. */ | ||
int ch) /* The Unicode character to be displayed. */ | ||
{ | ||
HDC hdc; | ||
int i, j, k; | ||
CanUse canUse; | ||
char **aliases, **anyFallbacks; | ||
char ***fontFallbacks; | ||
char *fallbackName; | ||
SubFont *subFontPtr; | ||
Tcl_DString ds; | ||
if (ch < BASE_CHARS) { | ||
return &fontPtr->subFontArray[0]; | ||
} | ||
for (i = 0; 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(&ds); | ||
hdc = GetDC(fontPtr->hwnd); | ||
aliases = TkFontGetAliasList(fontPtr->font.fa.family); | ||
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(hdc, fontPtr, fallbackName, | ||
ch, &ds); | ||
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(hdc, fontPtr, fallbackName, | ||
ch, &ds); | ||
if (subFontPtr != NULL) { | ||
goto end; | ||
} | ||
} | ||
/* | ||
* Try all face names available in the whole system until we | ||
* find one that can be used. | ||
*/ | ||
canUse.hdc = hdc; | ||
canUse.fontPtr = fontPtr; | ||
canUse.nameTriedPtr = &ds; | ||
canUse.ch = ch; | ||
canUse.subFontPtr = NULL; | ||
if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { | ||
EnumFontFamiliesW(hdc, NULL, (FONTENUMPROCW) WinFontCanUseProc, | ||
(LPARAM) &canUse); | ||
} else { | ||
EnumFontFamiliesA(hdc, NULL, (FONTENUMPROCA) WinFontCanUseProc, | ||
(LPARAM) &canUse); | ||
} | ||
subFontPtr = canUse.subFontPtr; | ||
end: | ||
Tcl_DStringFree(&ds); | ||
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); | ||
} | ||
ReleaseDC(fontPtr->hwnd, hdc); | ||
return subFontPtr; | ||
} | ||
static int CALLBACK | ||
WinFontCanUseProc( | ||
ENUMLOGFONT *lfPtr, /* Logical-font data. */ | ||
NEWTEXTMETRIC *tmPtr, /* Physical-font data (not used). */ | ||
int fontType, /* Type of font (not used). */ | ||
LPARAM lParam) /* Result object to hold result. */ | ||
{ | ||
int ch; | ||
HDC hdc; | ||
WinFont *fontPtr; | ||
CanUse *canUsePtr; | ||
char *fallbackName; | ||
SubFont *subFontPtr; | ||
Tcl_DString faceString; | ||
Tcl_DString *nameTriedPtr; | ||
canUsePtr = (CanUse *) lParam; | ||
ch = canUsePtr->ch; | ||
hdc = canUsePtr->hdc; | ||
fontPtr = canUsePtr->fontPtr; | ||
nameTriedPtr = canUsePtr->nameTriedPtr; | ||
fallbackName = lfPtr->elfLogFont.lfFaceName; | ||
Tcl_ExternalToUtfDString(systemEncoding, fallbackName, -1, &faceString); | ||
fallbackName = Tcl_DStringValue(&faceString); | ||
if (SeenName(fallbackName, nameTriedPtr) == 0) { | ||
subFontPtr = CanUseFallback(hdc, fontPtr, fallbackName, ch); | ||
if (subFontPtr != NULL) { | ||
canUsePtr->subFontPtr = subFontPtr; | ||
Tcl_DStringFree(&faceString); | ||
return 0; | ||
} | ||
} | ||
Tcl_DStringFree(&faceString); | ||
return 1; | ||
} | ||
/* | ||
*------------------------------------------------------------------------- | ||
* | ||
* 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 int | ||
FontMapLookup( | ||
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 void | ||
FontMapInsert( | ||
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 void | ||
FontMapLoadPage( | ||
SubFont *subFontPtr, /* Contains font mapping cache to be | ||
* updated. */ | ||
int row) /* Index of the page to be loaded into | ||
* the cache. */ | ||
{ | ||
FontFamily *familyPtr; | ||
Tcl_Encoding encoding; | ||
char src[TCL_UTF_MAX], buf[16]; | ||
USHORT *startCount, *endCount; | ||
int i, j, bitOffset, end, segCount; | ||
subFontPtr->fontMap[row] = (char *) ckalloc(FONTMAP_BITSPERPAGE / 8); | ||
memset(subFontPtr->fontMap[row], 0, FONTMAP_BITSPERPAGE / 8); | ||
familyPtr = subFontPtr->familyPtr; | ||
encoding = familyPtr->encoding; | ||
if (familyPtr->encoding == unicodeEncoding) { | ||
/* | ||
* Font is Unicode. Few fonts are going to have all characters, so | ||
* examine the TrueType character existence metrics to determine | ||
* what characters actually exist in this font. | ||
*/ | ||
segCount = familyPtr->segCount; | ||
startCount = familyPtr->startCount; | ||
endCount = familyPtr->endCount; | ||
j = 0; | ||
end = (row + 1) << FONTMAP_SHIFT; | ||
for (i = row << FONTMAP_SHIFT; i < end; i++) { | ||
for ( ; j < segCount; j++) { | ||
if (endCount[j] >= i) { | ||
if (startCount[j] <= i) { | ||
bitOffset = i & (FONTMAP_BITSPERPAGE - 1); | ||
subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7); | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
} else if (familyPtr->isSymbolFont) { | ||
/* | ||
* Assume that a symbol font with a known encoding has all the | ||
* characters that its encoding claims it supports. | ||
* | ||
* The test for "encoding == unicodeEncoding" | ||
* must occur before this case, to catch all symbol fonts (such | ||
* as {Comic Sans MS} or Wingdings) for which we don't have | ||
* encoding information; those symbol fonts are treated as if | ||
* they were in the Unicode encoding and their symbolic | ||
* character existence metrics are treated as if they were Unicode | ||
* character existence metrics. This way, although we don't know | ||
* the proper Unicode -> symbol font mapping, we can install the | ||
* symbol font as the base font and access its glyphs. | ||
*/ | ||
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, | ||
buf, sizeof(buf), NULL, NULL, NULL) != TCL_OK) { | ||
continue; | ||
} | ||
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( | ||
HDC hdc, /* HDC in which font can be selected. */ | ||
WinFont *fontPtr, /* The font object that will own the new | ||
* screen font. */ | ||
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. */ | ||
{ | ||
int i; | ||
char **aliases; | ||
SubFont *subFontPtr; | ||
if (SeenName(faceName, nameTriedPtr) == 0) { | ||
subFontPtr = CanUseFallback(hdc, 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(hdc, 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 int | ||
SeenName( | ||
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) { | ||
return 1; | ||
} | ||
seen += strlen(seen) + 1; | ||
} | ||
Tcl_DStringAppend(dsPtr, (char *) name, (int) (strlen(name) + 1)); | ||
return 0; | ||
} | ||
/* | ||
*------------------------------------------------------------------------- | ||
* | ||
* CanUseFallback -- | ||
* | ||
* If the specified screen font has not already been loaded into | ||
* the font object, determine if it 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( | ||
HDC hdc, /* HDC in which font can be selected. */ | ||
WinFont *fontPtr, /* The font object that will own the new | ||
* screen font. */ | ||
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; | ||
HFONT hFont; | ||
SubFont subFont; | ||
if (FamilyExists(hdc, faceName) == 0) { | ||
return NULL; | ||
} | ||
/* | ||
* Skip all fonts we've already used. | ||
*/ | ||
for (i = 0; i < fontPtr->numSubFonts; i++) { | ||
if (faceName == fontPtr->subFontArray[i].familyPtr->faceName) { | ||
return NULL; | ||
} | ||
} | ||
/* | ||
* Load this font and see if it has the desired character. | ||
*/ | ||
hFont = GetScreenFont(&fontPtr->font.fa, faceName, fontPtr->pixelSize); | ||
InitSubFont(hdc, hFont, 0, &subFont); | ||
if (((ch < 256) && (subFont.familyPtr->isSymbolFont)) | ||
|| (FontMapLookup(&subFont, ch) == 0)) { | ||
/* | ||
* Don't use a symbol font as a fallback font for characters below | ||
* 256. | ||
*/ | ||
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]; | ||
} | ||
/* | ||
*--------------------------------------------------------------------------- | ||
* | ||
* GetScreenFont -- | ||
* | ||
* Given the name and other attributes, construct an HFONT. | ||
* This is where all the alias and fallback substitution bottoms | ||
* out. | ||
* | ||
* Results: | ||
* The screen font that corresponds to the attributes. | ||
* | ||
* Side effects: | ||
* None. | ||
* | ||
*--------------------------------------------------------------------------- | ||
*/ | ||
static HFONT | ||
GetScreenFont( | ||
CONST TkFontAttributes *faPtr, | ||
/* Desired font attributes for new HFONT. */ | ||
CONST char *faceName, /* Overrides font family specified in font | ||
* attributes. */ | ||
int pixelSize) /* Overrides size specified in font | ||
* attributes. */ | ||
{ | ||
Tcl_DString ds; | ||
HFONT hFont; | ||
LOGFONTW lf; | ||
lf.lfHeight = -pixelSize; | ||
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_TT_PRECIS; | ||
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; | ||
lf.lfQuality = DEFAULT_QUALITY; | ||
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; | ||
Tcl_UtfToExternalDString(systemEncoding, faceName, -1, &ds); | ||
if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { | ||
Tcl_UniChar *src, *dst; | ||
/* | ||
* We can only store up to LF_FACESIZE wide characters | ||
*/ | ||
if (Tcl_DStringLength(&ds) >= (LF_FACESIZE * sizeof(WCHAR))) { | ||
Tcl_DStringSetLength(&ds, LF_FACESIZE); | ||
} | ||
src = (Tcl_UniChar *) Tcl_DStringValue(&ds); | ||
dst = (Tcl_UniChar *) lf.lfFaceName; | ||
while (*src != '\0') { | ||
*dst++ = *src++; | ||
} | ||
*dst = '\0'; | ||
hFont = CreateFontIndirectW(&lf); | ||
} else { | ||
/* | ||
* We can only store up to LF_FACESIZE characters | ||
*/ | ||
if (Tcl_DStringLength(&ds) >= LF_FACESIZE) { | ||
Tcl_DStringSetLength(&ds, LF_FACESIZE); | ||
} | ||
strcpy((char *) lf.lfFaceName, Tcl_DStringValue(&ds)); | ||
hFont = CreateFontIndirectA((LOGFONTA *) &lf); | ||
} | ||
Tcl_DStringFree(&ds); | ||
return hFont; | ||
} | ||
/* | ||
*------------------------------------------------------------------------- | ||
* | ||
* FamilyExists, FamilyOrAliasExists, WinFontExistsProc -- | ||
* | ||
* 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. | ||
* | ||
* Side effects: | ||
* None. | ||
* | ||
*------------------------------------------------------------------------- | ||
*/ | ||
static int | ||
FamilyExists( | ||
HDC hdc, /* HDC in which font family will be used. */ | ||
CONST char *faceName) /* Font family to query. */ | ||
{ | ||
int result; | ||
Tcl_DString faceString; | ||
/* | ||
* Just immediately rule out the following fonts, because they look so | ||
* ugly on windows. The caller's fallback mechanism will cause the | ||
* corresponding appropriate TrueType fonts to be selected. | ||
*/ | ||
if (strcasecmp(faceName, "Courier") == 0) { | ||
return 0; | ||
} | ||
if (strcasecmp(faceName, "Times") == 0) { | ||
return 0; | ||
} | ||
if (strcasecmp(faceName, "Helvetica") == 0) { | ||
return 0; | ||
} | ||
Tcl_UtfToExternalDString(systemEncoding, faceName, -1, &faceString); | ||
/* | ||
* If the family exists, WinFontExistProc() will be called and | ||
* EnumFontFamilies() will return whatever WinFontExistProc() returns. | ||
* If the family doesn't exist, EnumFontFamilies() will just return a | ||
* non-zero value. | ||
*/ | ||
if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { | ||
result = EnumFontFamiliesW(hdc, (WCHAR *) Tcl_DStringValue(&faceString), | ||
(FONTENUMPROCW) WinFontExistProc, 0); | ||
} else { | ||
result = EnumFontFamiliesA(hdc, (char *) Tcl_DStringValue(&faceString), | ||
(FONTENUMPROCA) WinFontExistProc, 0); | ||
} | ||
Tcl_DStringFree(&faceString); | ||
return (result == 0); | ||
} | ||
static char * | ||
FamilyOrAliasExists( | ||
HDC hdc, | ||
CONST char *faceName) | ||
{ | ||
char **aliases; | ||
int i; | ||
if (FamilyExists(hdc, faceName) != 0) { | ||
return (char *) faceName; | ||
} | ||
aliases = TkFontGetAliasList(faceName); | ||
if (aliases != NULL) { | ||
for (i = 0; aliases[i] != NULL; i++) { | ||
if (FamilyExists(hdc, aliases[i]) != 0) { | ||
return aliases[i]; | ||
} | ||
} | ||
} | ||
return NULL; | ||
} | ||
static int CALLBACK | ||
WinFontExistProc( | ||
ENUMLOGFONT *lfPtr, /* Logical-font data. */ | ||
NEWTEXTMETRIC *tmPtr, /* Physical-font data (not used). */ | ||
int fontType, /* Type of font (not used). */ | ||
LPARAM lParam) /* EnumFontData to hold result. */ | ||
{ | ||
return 0; | ||
} | ||
/* | ||
* The following data structures are used when querying a TrueType font file | ||
* to determine which characters the font supports. | ||
*/ | ||
#pragma pack(1) /* Structures are byte aligned in file. */ | ||
#define CMAPHEX 0x636d6170 /* Key for character map resource. */ | ||
typedef struct CMAPTABLE { | ||
USHORT version; /* Table version number (0). */ | ||
USHORT numTables; /* Number of encoding tables following. */ | ||
} CMAPTABLE; | ||
typedef struct ENCODINGTABLE { | ||
USHORT platform; /* Platform for which data is targeted. | ||
* 3 means data is for Windows. */ | ||
USHORT encoding; /* How characters in font are encoded. | ||
* 1 means that the following subtable is | ||
* keyed based on Unicode. */ | ||
ULONG offset; /* Byte offset from beginning of CMAPTABLE | ||
* to the subtable for this encoding. */ | ||
} ENCODINGTABLE; | ||
typedef struct ANYTABLE { | ||
USHORT format; /* Format number. */ | ||
USHORT length; /* The actual length in bytes of this | ||
* subtable. */ | ||
USHORT version; /* Version number (starts at 0). */ | ||
} ANYTABLE; | ||
typedef struct BYTETABLE { | ||
USHORT format; /* Format number is set to 0. */ | ||
USHORT length; /* The actual length in bytes of this | ||
* subtable. */ | ||
USHORT version; /* Version number (starts at 0). */ | ||
BYTE glyphIdArray[256]; /* Array that maps up to 256 single-byte char | ||
* codes to glyph indices. */ | ||
} BYTETABLE; | ||
typedef struct SUBHEADER { | ||
USHORT firstCode; /* First valid low byte for subHeader. */ | ||
USHORT entryCount; /* Number valid low bytes for subHeader. */ | ||
SHORT idDelta; /* Constant adder to get base glyph index. */ | ||
USHORT idRangeOffset; /* Byte offset from here to appropriate | ||
* glyphIndexArray. */ | ||
} SUBHEADER; | ||
typedef struct HIBYTETABLE { | ||
USHORT format; /* Format number is set to 2. */ | ||
USHORT length; /* The actual length in bytes of this | ||
* subtable. */ | ||
USHORT version; /* Version number (starts at 0). */ | ||
USHORT subHeaderKeys[256]; /* Maps high bytes to subHeaders: value is | ||
* subHeader index * 8. */ | ||
#if 0 | ||
SUBHEADER subHeaders[]; /* Variable-length array of SUBHEADERs. */ | ||
USHORT glyphIndexArray[]; /* Variable-length array containing subarrays | ||
* used for mapping the low byte of 2-byte | ||
* characters. */ | ||
#endif | ||
} HIBYTETABLE; | ||
typedef struct SEGMENTTABLE { | ||
USHORT format; /* Format number is set to 4. */ | ||
USHORT length; /* The actual length in bytes of this | ||
* subtable. */ | ||
USHORT version; /* Version number (starts at 0). */ | ||
USHORT segCountX2; /* 2 x segCount. */ | ||
USHORT searchRange; /* 2 x (2**floor(log2(segCount))). */ | ||
USHORT entrySelector; /* log2(searchRange/2). */ | ||
USHORT rangeShift; /* 2 x segCount - searchRange. */ | ||
#if 0 | ||
USHORT endCount[segCount] /* End characterCode for each segment. */ | ||
USHORT reservedPad; /* Set to 0. */ | ||
USHORT startCount[segCount];/* Start character code for each segment. */ | ||
USHORT idDelta[segCount]; /* Delta for all character in segment. */ | ||
USHORT idRangeOffset[segCount]; /* Offsets into glyphIdArray or 0. */ | ||
USHORT glyphIdArray[] /* Glyph index array. */ | ||
#endif | ||
} SEGMENTTABLE; | ||
typedef struct TRIMMEDTABLE { | ||
USHORT format; /* Format number is set to 6. */ | ||
USHORT length; /* The actual length in bytes of this | ||
* subtable. */ | ||
USHORT version; /* Version number (starts at 0). */ | ||
USHORT firstCode; /* First character code of subrange. */ | ||
USHORT entryCount; /* Number of character codes in subrange. */ | ||
#if 0 | ||
USHORT glyphIdArray[]; /* Array of glyph index values for | ||
character codes in the range. */ | ||
#endif | ||
} TRIMMEDTABLE; | ||
typedef union SUBTABLE { | ||
ANYTABLE any; | ||
BYTETABLE byte; | ||
HIBYTETABLE hiByte; | ||
SEGMENTTABLE segment; | ||
TRIMMEDTABLE trimmed; | ||
} SUBTABLE; | ||
#pragma pack() | ||
/* | ||
*------------------------------------------------------------------------- | ||
* | ||
* LoadFontRanges -- | ||
* | ||
* Given an HFONT, get the information about the characters that | ||
* this font can display. | ||
* | ||
* Results: | ||
* If the font has no Unicode character information, the return value | ||
* is 0 and *startCountPtr and *endCountPtr are filled with NULL. | ||
* Otherwise, *startCountPtr and *endCountPtr are set to pointers to | ||
* arrays of TrueType character existence information and the return | ||
* value is the length of the arrays (the two arrays are always the | ||
* same length as each other). | ||
* | ||
* Side effects: | ||
* None. | ||
* | ||
*------------------------------------------------------------------------- | ||
*/ | ||
static int | ||
LoadFontRanges( | ||
HDC hdc, /* HDC into which font can be selected. */ | ||
HFONT hFont, /* HFONT to query. */ | ||
USHORT **startCountPtr, /* Filled with malloced pointer to | ||
* character range information. */ | ||
USHORT **endCountPtr, /* Filled with malloced pointer to | ||
* character range information. */ | ||
int *symbolPtr) | ||
{ | ||
int n, i, swapped, offset, cbData, segCount; | ||
DWORD cmapKey; | ||
USHORT *startCount, *endCount; | ||
CMAPTABLE cmapTable; | ||
ENCODINGTABLE encTable; | ||
SUBTABLE subTable; | ||
char *s; | ||
segCount = 0; | ||
startCount = NULL; | ||
endCount = NULL; | ||
*symbolPtr = 0; | ||
hFont = SelectObject(hdc, hFont); | ||
i = 0; | ||
s = (char *) &i; | ||
*s = '\1'; | ||
swapped = 0; | ||
if (i == 1) { | ||
swapped = 1; | ||
} | ||
cmapKey = CMAPHEX; | ||
if (swapped) { | ||
SwapLong(&cmapKey); | ||
} | ||
n = GetFontData(hdc, cmapKey, 0, &cmapTable, sizeof(cmapTable)); | ||
if (n != GDI_ERROR) { | ||
if (swapped) { | ||
SwapShort(&cmapTable.numTables); | ||
} | ||
for (i = 0; i < cmapTable.numTables; i++) { | ||
offset = sizeof(cmapTable) + i * sizeof(encTable); | ||
GetFontData(hdc, cmapKey, offset, &encTable, sizeof(encTable)); | ||
if (swapped) { | ||
SwapShort(&encTable.platform); | ||
SwapShort(&encTable.encoding); | ||
SwapLong(&encTable.offset); | ||
} | ||
if (encTable.platform != 3) { | ||
/* | ||
* Not Microsoft encoding. | ||
*/ | ||
continue; | ||
} | ||
if (encTable.encoding == 0) { | ||
*symbolPtr = 1; | ||
} else if (encTable.encoding != 1) { | ||
continue; | ||
} | ||
GetFontData(hdc, cmapKey, encTable.offset, &subTable, | ||
sizeof(subTable)); | ||
if (swapped) { | ||
SwapShort(&subTable.any.format); | ||
} | ||
if (subTable.any.format == 4) { | ||
if (swapped) { | ||
SwapShort(&subTable.segment.segCountX2); | ||
} | ||
segCount = subTable.segment.segCountX2 / 2; | ||
cbData = segCount * sizeof(USHORT); | ||
startCount = (USHORT *) ckalloc(cbData); | ||
endCount = (USHORT *) ckalloc(cbData); | ||
offset = encTable.offset + sizeof(subTable.segment); | ||
GetFontData(hdc, cmapKey, offset, endCount, cbData); | ||
offset += cbData + sizeof(USHORT); | ||
GetFontData(hdc, cmapKey, offset, startCount, cbData); | ||
if (swapped) { | ||
for (i = 0; i < segCount; i++) { | ||
SwapShort(&endCount[i]); | ||
SwapShort(&startCount[i]); | ||
} | ||
} | ||
if (*symbolPtr != 0) { | ||
/* | ||
* Empirically determined: When a symbol font is | ||
* loaded, the character existence metrics obtained | ||
* from the system are mildly wrong. If the real range | ||
* of the symbol font is from 0020 to 00FE, then the | ||
* metrics are reported as F020 to F0FE. When we load | ||
* a symbol font, we must fix the character existence | ||
* metrics. | ||
* | ||
* Symbol fonts should only use the symbol encoding | ||
* for 8-bit characters [note Bug: 2406] | ||
*/ | ||
for (i = 0; i < segCount; i++) { | ||
if (((startCount[i] & 0xff00) == 0xf000) | ||
&& ((endCount[i] & 0xff00) == 0xf000)) { | ||
startCount[i] &= 0xff; | ||
endCount[i] &= 0xff; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
SelectObject(hdc, hFont); | ||
*startCountPtr = startCount; | ||
*endCountPtr = endCount; | ||
return segCount; | ||
} | ||
/* | ||
*------------------------------------------------------------------------- | ||
* | ||
* SwapShort, SwapLong -- | ||
* | ||
* Helper functions to convert the data loaded from TrueType font | ||
* files to Intel byte ordering. | ||
* | ||
* Results: | ||
* Bytes of input value are swapped and stored back in argument. | ||
* | ||
* Side effects: | ||
* None. | ||
* | ||
*------------------------------------------------------------------------- | ||
*/ | ||
static void | ||
SwapShort(PUSHORT p) | ||
{ | ||
*p = (SHORT)(HIBYTE(*p) + (LOBYTE(*p) << 8)); | ||
} | ||
static void | ||
SwapLong(PULONG p) | ||
{ | ||
ULONG temp; | ||
temp = (LONG) ((BYTE) *p); | ||
temp <<= 8; | ||
*p >>=8; | ||
temp += (LONG) ((BYTE) *p); | ||
temp <<= 8; | ||
*p >>=8; | ||
temp += (LONG) ((BYTE) *p); | ||
temp <<= 8; | ||
*p >>=8; | ||
temp += (LONG) ((BYTE) *p); | ||
*p = temp; | ||
} | ||
/* $History: tkWinFont.c $ | ||
* | ||
* ***************** Version 1 ***************** | ||
* User: Dtashley Date: 1/02/01 Time: 3:15a | ||
* Created in $/IjuScripter, IjuConsole/Source/Tk Base | ||
* Initial check-in. | ||
*/ | ||
/* End of TKWINFONT.C */ | ||
1 | /* $Header$ */ | |
2 | ||
3 | /* | |
4 | * tkWinFont.c -- | |
5 | * | |
6 | * Contains the Windows implementation of the platform-independant | |
7 | * font package interface. | |
8 | * | |
9 | * Copyright (c) 1994 Software Research Associates, Inc. | |
10 | * Copyright (c) 1995-1997 Sun Microsystems, Inc. | |
11 | * Copyright (c) 1998-1999 by Scriptics Corporation. | |
12 | * | |
13 | * See the file "license.terms" for information on usage and redistribution | |
14 | * of this file, and for a DISCLAIMER OF ALL WARRANTIES. | |
15 | * | |
16 | * RCS: @(#) $Id: tkwinfont.c,v 1.1.1.1 2001/06/13 05:13:30 dtashley Exp $ | |
17 | */ | |
18 | ||
19 | #include "tkWinInt.h" | |
20 | #include "tkFont.h" | |
21 | ||
22 | /* | |
23 | * The following structure represents a font family. It is assumed that | |
24 | * all screen fonts constructed from the same "font family" share certain | |
25 | * properties; all screen fonts with the same "font family" point to a | |
26 | * shared instance of this structure. The most important shared property | |
27 | * is the character existence metrics, used to determine if a screen font | |
28 | * can display a given Unicode character. | |
29 | * | |
30 | * Under Windows, a "font family" is uniquely identified by its face name. | |
31 | */ | |
32 | ||
33 | #define FONTMAP_SHIFT 10 | |
34 | ||
35 | #define FONTMAP_PAGES (1 << (sizeof(Tcl_UniChar)*8 - FONTMAP_SHIFT)) | |
36 | #define FONTMAP_BITSPERPAGE (1 << FONTMAP_SHIFT) | |
37 | ||
38 | typedef struct FontFamily { | |
39 | struct FontFamily *nextPtr; /* Next in list of all known font families. */ | |
40 | int refCount; /* How many SubFonts are referring to this | |
41 | * FontFamily. When the refCount drops to | |
42 | * zero, this FontFamily may be freed. */ | |
43 | /* | |
44 | * Key. | |
45 | */ | |
46 | ||
47 | Tk_Uid faceName; /* Face name key for this FontFamily. */ | |
48 | ||
49 | /* | |
50 | * Derived properties. | |
51 | */ | |
52 | ||
53 | Tcl_Encoding encoding; /* Encoding for this font family. */ | |
54 | int isSymbolFont; /* Non-zero if this is a symbol font. */ | |
55 | int isWideFont; /* 1 if this is a double-byte font, 0 | |
56 | * otherwise. */ | |
57 | BOOL (WINAPI *textOutProc)(HDC, int, int, TCHAR *, int); | |
58 | /* The procedure to use to draw text after | |
59 | * it has been converted from UTF-8 to the | |
60 | * encoding of this font. */ | |
61 | BOOL (WINAPI *getTextExtentPoint32Proc)(HDC, TCHAR *, int, LPSIZE); | |
62 | /* The procedure to use to measure text after | |
63 | * it has been converted from UTF-8 to the | |
64 | * encoding of this font. */ | |
65 | ||
66 | char *fontMap[FONTMAP_PAGES]; | |
67 | /* Two-level sparse table used to determine | |
68 | * quickly if the specified character exists. | |
69 | * As characters are encountered, more pages | |
70 | * in this table are dynamically added. The | |
71 | * contents of each page is a bitmask | |
72 | * consisting of FONTMAP_BITSPERPAGE bits, | |
73 | * representing whether this font can be used | |
74 | * to display the given character at the | |
75 | * corresponding bit position. The high bits | |
76 | * of the character are used to pick which | |
77 | * page of the table is used. */ | |
78 | ||
79 | /* | |
80 | * Cached Truetype font info. | |
81 | */ | |
82 | ||
83 | int segCount; /* The length of the following arrays. */ | |
84 | USHORT *startCount; /* Truetype information about the font, */ | |
85 | USHORT *endCount; /* indicating which characters this font | |
86 | * can display (malloced). The format of | |
87 | * this information is (relatively) compact, | |
88 | * but would take longer to search than | |
89 | * indexing into the fontMap[][] table. */ | |
90 | } FontFamily; | |
91 | ||
92 | /* | |
93 | * The following structure encapsulates an individual screen font. A font | |
94 | * object is made up of however many SubFonts are necessary to display a | |
95 | * stream of multilingual characters. | |
96 | */ | |
97 | ||
98 | typedef struct SubFont { | |
99 | char **fontMap; /* Pointer to font map from the FontFamily, | |
100 | * cached here to save a dereference. */ | |
101 | HFONT hFont; /* The specific screen font that will be | |
102 | * used when displaying/measuring chars | |
103 | * belonging to the FontFamily. */ | |
104 | FontFamily *familyPtr; /* The FontFamily for this SubFont. */ | |
105 | } SubFont; | |
106 | ||
107 | /* | |
108 | * The following structure represents Windows' implementation of a font | |
109 | * object. | |
110 | */ | |
111 | ||
112 | #define SUBFONT_SPACE 3 | |
113 | #define BASE_CHARS 128 | |
114 | ||
115 | typedef struct WinFont { | |
116 | TkFont font; /* Stuff used by generic font package. Must | |
117 | * be first in structure. */ | |
118 | SubFont staticSubFonts[SUBFONT_SPACE]; | |
119 | /* Builtin space for a limited number of | |
120 | * SubFonts. */ | |
121 | int numSubFonts; /* Length of following array. */ | |
122 | SubFont *subFontArray; /* Array of SubFonts that have been loaded | |
123 | * in order to draw/measure all the characters | |
124 | * encountered by this font so far. All fonts | |
125 | * start off with one SubFont initialized by | |
126 | * AllocFont() from the original set of font | |
127 | * attributes. Usually points to | |
128 | * staticSubFonts, but may point to malloced | |
129 | * space if there are lots of SubFonts. */ | |
130 | ||
131 | HWND hwnd; /* Toplevel window of application that owns | |
132 | * this font, used for getting HDC for | |
133 | * offscreen measurements. */ | |
134 | int pixelSize; /* Original pixel size used when font was | |
135 | * constructed. */ | |
136 | int widths[BASE_CHARS]; /* Widths of first 128 chars in the base | |
137 | * font, for handling common case. The base | |
138 | * font is always used to draw characters | |
139 | * between 0x0000 and 0x007f. */ | |
140 | } WinFont; | |
141 | ||
142 | /* | |
143 | * The following structure is passed as the LPARAM when calling the font | |
144 | * enumeration procedure to determine if a font can support the given | |
145 | * character. | |
146 | */ | |
147 | ||
148 | typedef struct CanUse { | |
149 | HDC hdc; | |
150 | WinFont *fontPtr; | |
151 | Tcl_DString *nameTriedPtr; | |
152 | int ch; | |
153 | SubFont *subFontPtr; | |
154 | } CanUse; | |
155 | ||
156 | /* | |
157 | * The following structure is used to map between the Tcl strings that | |
158 | * represent the system fonts and the numbers used by Windows. | |
159 | */ | |
160 | ||
161 | static TkStateMap systemMap[] = { | |
162 | {ANSI_FIXED_FONT, "ansifixed"}, | |
163 | {ANSI_VAR_FONT, "ansi"}, | |
164 | {DEVICE_DEFAULT_FONT, "device"}, | |
165 | {OEM_FIXED_FONT, "oemfixed"}, | |
166 | {SYSTEM_FIXED_FONT, "systemfixed"}, | |
167 | {SYSTEM_FONT, "system"}, | |
168 | {-1, NULL} | |
169 | }; | |
170 | ||
171 | typedef struct ThreadSpecificData { | |
172 | FontFamily *fontFamilyList; /* The list of font families that are | |
173 | * currently loaded. As screen fonts | |
174 | * are loaded, this list grows to hold | |
175 | * information about what characters | |
176 | * exist in each font family. */ | |
177 | Tcl_HashTable uidTable; | |
178 | } ThreadSpecificData; | |
179 | static Tcl_ThreadDataKey dataKey; | |
180 | ||
181 | /* | |
182 | * Information cached about the system at startup time. | |
183 | */ | |
184 | ||
185 | static Tcl_Encoding unicodeEncoding; | |
186 | static Tcl_Encoding systemEncoding; | |
187 | ||
188 | /* | |
189 | * Procedures used only in this file. | |
190 | */ | |
191 | ||
192 | static FontFamily * AllocFontFamily(HDC hdc, HFONT hFont, int base); | |
193 | static SubFont * CanUseFallback(HDC hdc, WinFont *fontPtr, | |
194 | char *fallbackName, int ch); | |
195 | static SubFont * CanUseFallbackWithAliases(HDC hdc, WinFont *fontPtr, | |
196 | char *faceName, int ch, Tcl_DString *nameTriedPtr); | |
197 | static int FamilyExists(HDC hdc, CONST char *faceName); | |
198 | static char * FamilyOrAliasExists(HDC hdc, CONST char *faceName); | |
199 | static SubFont * FindSubFontForChar(WinFont *fontPtr, int ch); | |
200 | static void FontMapInsert(SubFont *subFontPtr, int ch); | |
201 | static void FontMapLoadPage(SubFont *subFontPtr, int row); | |
202 | static int FontMapLookup(SubFont *subFontPtr, int ch); | |
203 | static void FreeFontFamily(FontFamily *familyPtr); | |
204 | static HFONT GetScreenFont(CONST TkFontAttributes *faPtr, | |
205 | CONST char *faceName, int pixelSize); | |
206 | static void InitFont(Tk_Window tkwin, HFONT hFont, | |
207 | int overstrike, WinFont *tkFontPtr); | |
208 | static void InitSubFont(HDC hdc, HFONT hFont, int base, | |
209 | SubFont *subFontPtr); | |
210 | static int LoadFontRanges(HDC hdc, HFONT hFont, | |
211 | USHORT **startCount, USHORT **endCount, | |
212 | int *symbolPtr); | |
213 | static void MultiFontTextOut(HDC hdc, WinFont *fontPtr, | |
214 | CONST char *source, int numBytes, int x, int y); | |
215 | static void ReleaseFont(WinFont *fontPtr); | |
216 | static void ReleaseSubFont(SubFont *subFontPtr); | |
217 | static int SeenName(CONST char *name, Tcl_DString *dsPtr); | |
218 | static void SwapLong(PULONG p); | |
219 | static void SwapShort(USHORT *p); | |
220 | static int CALLBACK WinFontCanUseProc(ENUMLOGFONT *lfPtr, | |
221 | NEWTEXTMETRIC *tmPtr, int fontType, | |
222 | LPARAM lParam); | |
223 | static int CALLBACK WinFontExistProc(ENUMLOGFONT *lfPtr, | |
224 | NEWTEXTMETRIC *tmPtr, int fontType, | |
225 | LPARAM lParam); | |
226 | static int CALLBACK WinFontFamilyEnumProc(ENUMLOGFONT *lfPtr, | |
227 | NEWTEXTMETRIC *tmPtr, int fontType, | |
228 | LPARAM lParam); | |
229 | ||
230 | /* | |
231 | *------------------------------------------------------------------------- | |
232 | * | |
233 | * TkpFontPkgInit -- | |
234 | * | |
235 | * This procedure is called when an application is created. It | |
236 | * initializes all the structures that are used by the | |
237 | * platform-dependent code on a per application basis. | |
238 | * | |
239 | * Results: | |
240 | * None. | |
241 | * | |
242 | * Side effects: | |
243 | * | |
244 | * None. | |
245 | * | |
246 | *------------------------------------------------------------------------- | |
247 | */ | |
248 | ||
249 | void | |
250 | TkpFontPkgInit( | |
251 | TkMainInfo *mainPtr) /* The application being created. */ | |
252 | { | |
253 | unicodeEncoding = Tcl_GetEncoding(NULL, "unicode"); | |
254 | if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { | |
255 | /* | |
256 | * If running NT, then we will be calling some Unicode functions | |
257 | * explictly. So, even if the Tcl system encoding isn't Unicode, | |
258 | * make sure we convert to/from the Unicode char set. | |
259 | */ | |
260 | ||
261 | systemEncoding = unicodeEncoding; | |
262 | } | |
263 | } | |
264 | ||
265 | /* | |
266 | *--------------------------------------------------------------------------- | |
267 | * | |
268 | * TkpGetNativeFont -- | |
269 | * | |
270 | * Map a platform-specific native font name to a TkFont. | |
271 | * | |
272 | * Results: | |
273 | * The return value is a pointer to a TkFont that represents the | |
274 | * native font. If a native font by the given name could not be | |
275 | * found, the return value is NULL. | |
276 | * | |
277 | * Every call to this procedure returns a new TkFont structure, | |
278 | * even if the name has already been seen before. The caller should | |
279 | * call TkpDeleteFont() when the font is no longer needed. | |
280 | * | |
281 | * The caller is responsible for initializing the memory associated | |
282 | * with the generic TkFont when this function returns and releasing | |
283 | * the contents of the generic TkFont before calling TkpDeleteFont(). | |
284 | * | |
285 | * Side effects: | |
286 | * Memory allocated. | |
287 | * | |
288 | *--------------------------------------------------------------------------- | |
289 | */ | |
290 | ||
291 | TkFont * | |
292 | TkpGetNativeFont( | |
293 | Tk_Window tkwin, /* For display where font will be used. */ | |
294 | CONST char *name) /* Platform-specific font name. */ | |
295 | { | |
296 | int object; | |
297 | WinFont *fontPtr; | |
298 | ||
299 | object = TkFindStateNum(NULL, NULL, systemMap, name); | |
300 | if (object < 0) { | |
301 | return NULL; | |
302 | } | |
303 | ||
304 | tkwin = (Tk_Window) ((TkWindow *) tkwin)->mainPtr->winPtr; | |
305 | fontPtr = (WinFont *) ckalloc(sizeof(WinFont)); | |
306 | InitFont(tkwin, GetStockObject(object), 0, fontPtr); | |
307 | ||
308 | return (TkFont *) fontPtr; | |
309 | } | |
310 | ||
311 | /* | |
312 | *--------------------------------------------------------------------------- | |
313 | * | |
314 | * TkpGetFontFromAttributes -- | |
315 | * | |
316 | * Given a desired set of attributes for a font, find a font with | |
317 | * the closest matching attributes. | |
318 | * | |
319 | * Results: | |
320 | * The return value is a pointer to a TkFont that represents the | |
321 | * font with the desired attributes. If a font with the desired | |
322 | * attributes could not be constructed, some other font will be | |
323 | * substituted automatically. NULL is never returned. | |
324 | * | |
325 | * Every call to this procedure returns a new TkFont structure, | |
326 | * even if the specified attributes have already been seen before. | |
327 | * The caller should call TkpDeleteFont() to free the platform- | |
328 | * specific data when the font is no longer needed. | |
329 | * | |
330 | * The caller is responsible for initializing the memory associated | |
331 | * with the generic TkFont when this function returns and releasing | |
332 | * the contents of the generic TkFont before calling TkpDeleteFont(). | |
333 | * | |
334 | * Side effects: | |
335 | * Memory allocated. | |
336 | * | |
337 | *--------------------------------------------------------------------------- | |
338 | */ | |
339 | ||
340 | TkFont * | |
341 | TkpGetFontFromAttributes( | |
342 | TkFont *tkFontPtr, /* If non-NULL, store the information in | |
343 | * this existing TkFont structure, rather than | |
344 | * allocating a new structure to hold the | |
345 | * font; the existing contents of the font | |
346 | * will be released. If NULL, a new TkFont | |
347 | * structure is allocated. */ | |
348 | Tk_Window tkwin, /* For display where font will be used. */ | |
349 | CONST TkFontAttributes *faPtr) | |
350 | /* Set of attributes to match. */ | |
351 | { | |
352 | int i, j; | |
353 | HDC hdc; | |
354 | HWND hwnd; | |
355 | HFONT hFont; | |
356 | Window window; | |
357 | WinFont *fontPtr; | |
358 | char ***fontFallbacks; | |
359 | char *faceName, *fallback, *actualName; | |
360 | ||
361 | tkwin = (Tk_Window) ((TkWindow *) tkwin)->mainPtr->winPtr; | |
362 | window = Tk_WindowId(tkwin); | |
363 | hwnd = (window == None) ? NULL : TkWinGetHWND(window); | |
364 | hdc = GetDC(hwnd); | |
365 | ||
366 | /* | |
367 | * Algorithm to get the closest font name to the one requested. | |
368 | * | |
369 | * try fontname | |
370 | * try all aliases for fontname | |
371 | * foreach fallback for fontname | |
372 | * try the fallback | |
373 | * try all aliases for the fallback | |
374 | */ | |
375 | ||
376 | faceName = faPtr->family; | |
377 | if (faceName != NULL) { | |
378 | actualName = FamilyOrAliasExists(hdc, faceName); | |
379 | if (actualName != NULL) { | |
380 | faceName = actualName; | |
381 | goto found; | |
382 | } | |
383 | fontFallbacks = TkFontGetFallbacks(); | |
384 | for (i = 0; fontFallbacks[i] != NULL; i++) { | |
385 | for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) { | |
386 | if (strcasecmp(faceName, fallback) == 0) { | |
387 | break; | |
388 | } | |
389 | } | |
390 | if (fallback != NULL) { | |
391 | for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) { | |
392 | actualName = FamilyOrAliasExists(hdc, fallback); | |
393 | if (actualName != NULL) { | |
394 | faceName = actualName; | |
395 | goto found; | |
396 | } | |
397 | } | |
398 | } | |
399 | } | |
400 | } | |
401 | ||
402 | found: | |
403 | ReleaseDC(hwnd, hdc); | |
404 | ||
405 | hFont = GetScreenFont(faPtr, faceName, TkFontGetPixels(tkwin, faPtr->size)); | |
406 | if (tkFontPtr == NULL) { | |
407 | fontPtr = (WinFont *) ckalloc(sizeof(WinFont)); | |
408 | } else { | |
409 | fontPtr = (WinFont *) tkFontPtr; | |
410 | ReleaseFont(fontPtr); | |
411 | } | |
412 | InitFont(tkwin, hFont, faPtr->overstrike, fontPtr); | |
413 | ||
414 | return (TkFont *) fontPtr; | |
415 | } | |
416 | ||
417 | /* | |
418 | *--------------------------------------------------------------------------- | |
419 | * | |
420 | * TkpDeleteFont -- | |
421 | * | |
422 | * Called to release a font allocated by TkpGetNativeFont() or | |
423 | * TkpGetFontFromAttributes(). The caller should have already | |
424 | * released the fields of the TkFont that are used exclusively by | |
425 | * the generic TkFont code. | |
426 | * | |
427 | * Results: | |
428 | * None. | |
429 | * | |
430 | * Side effects: | |
431 | * TkFont is deallocated. | |
432 | * | |
433 | *--------------------------------------------------------------------------- | |
434 | */ | |
435 | ||
436 | void | |
437 | TkpDeleteFont( | |
438 | TkFont *tkFontPtr) /* Token of font to be deleted. */ | |
439 | { | |
440 | WinFont *fontPtr; | |
441 | ||
442 | fontPtr = (WinFont *) tkFontPtr; | |
443 | ReleaseFont(fontPtr); | |
444 | } | |
445 | ||
446 | /* | |
447 | *--------------------------------------------------------------------------- | |
448 | * | |
449 | * TkpGetFontFamilies, WinFontFamilyEnumProc -- | |
450 | * | |
451 | * Return information about the font families that are available | |
452 | * on the display of the given window. | |
453 | * | |
454 | * Results: | |
455 | * Modifies interp's result object to hold a list of all the available | |
456 | * font families. | |
457 | * | |
458 | * Side effects: | |
459 | * None. | |
460 | * | |
461 | *--------------------------------------------------------------------------- | |
462 | */ | |
463 | ||
464 | void | |
465 | TkpGetFontFamilies( | |
466 | Tcl_Interp *interp, /* Interp to hold result. */ | |
467 | Tk_Window tkwin) /* For display to query. */ | |
468 | { | |
469 | HDC hdc; | |
470 | HWND hwnd; | |
471 | Window window; | |
472 | ||
473 | window = Tk_WindowId(tkwin); | |
474 | hwnd = (window == None) ? NULL : TkWinGetHWND(window); | |
475 | hdc = GetDC(hwnd); | |
476 | ||
477 | /* | |
478 | * On any version NT, there may fonts with international names. | |
479 | * Use the NT-only Unicode version of EnumFontFamilies to get the | |
480 | * font names. If we used the ANSI version on a non-internationalized | |
481 | * version of NT, we would get font names with '?' replacing all | |
482 | * the international characters. | |
483 | * | |
484 | * On a non-internationalized verson of 95, fonts with international | |
485 | * names are not allowed, so the ANSI version of EnumFontFamilies will | |
486 | * work. On an internationalized version of 95, there may be fonts with | |
487 | * international names; the ANSI version will work, fetching the | |
488 | * name in the system code page. Can't use the Unicode version of | |
489 | * EnumFontFamilies because it only exists under NT. | |
490 | */ | |
491 | ||
492 | if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { | |
493 | EnumFontFamiliesW(hdc, NULL, (FONTENUMPROCW) WinFontFamilyEnumProc, | |
494 | (LPARAM) interp); | |
495 | } else { | |
496 | EnumFontFamiliesA(hdc, NULL, (FONTENUMPROCA) WinFontFamilyEnumProc, | |
497 | (LPARAM) interp); | |
498 | } | |
499 | ReleaseDC(hwnd, hdc); | |
500 | } | |
501 | ||
502 | static int CALLBACK | |
503 | WinFontFamilyEnumProc( | |
504 | ENUMLOGFONT *lfPtr, /* Logical-font data. */ | |
505 | NEWTEXTMETRIC *tmPtr, /* Physical-font data (not used). */ | |
506 | int fontType, /* Type of font (not used). */ | |
507 | LPARAM lParam) /* Result object to hold result. */ | |
508 | { | |
509 | char *faceName; | |
510 | Tcl_DString faceString; | |
511 | Tcl_Obj *strPtr; | |
512 | Tcl_Interp *interp; | |
513 | ||
514 | interp = (Tcl_Interp *) lParam; | |
515 | faceName = lfPtr->elfLogFont.lfFaceName; | |
516 | Tcl_ExternalToUtfDString(systemEncoding, faceName, -1, &faceString); | |
517 | strPtr = Tcl_NewStringObj(Tcl_DStringValue(&faceString), | |
518 | Tcl_DStringLength(&faceString)); | |
519 | Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), strPtr); | |
520 | Tcl_DStringFree(&faceString); | |
521 | return 1; | |
522 | } | |
523 | ||
524 | /* | |
525 | *------------------------------------------------------------------------- | |
526 | * | |
527 | * TkpGetSubFonts -- | |
528 | * | |
529 | * A function used by the testing package for querying the actual | |
530 | * screen fonts that make up a font object. | |
531 | * | |
532 | * Results: | |
533 | * Modifies interp's result object to hold a list containing the | |
534 | * names of the screen fonts that make up the given font object. | |
535 | * | |
536 | * Side effects: | |
537 | * None. | |
538 | * | |
539 | *------------------------------------------------------------------------- | |
540 | */ | |
541 | ||
542 | void | |
543 | TkpGetSubFonts( | |
544 | Tcl_Interp *interp, /* Interp to hold result. */ | |
545 | Tk_Font tkfont) /* Font object to query. */ | |
546 | { | |
547 | int i; | |
548 | WinFont *fontPtr; | |
549 | FontFamily *familyPtr; | |
550 | Tcl_Obj *resultPtr, *strPtr; | |
551 | ||
552 | resultPtr = Tcl_GetObjResult(interp); | |
553 | fontPtr = (WinFont *) tkfont; | |
554 | for (i = 0; i < fontPtr->numSubFonts; i++) { | |
555 | familyPtr = fontPtr->subFontArray[i].familyPtr; | |
556 | strPtr = Tcl_NewStringObj(familyPtr->faceName, -1); | |
557 | Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); | |
558 | } | |
559 | } | |
560 | ||
561 | /* | |
562 | *--------------------------------------------------------------------------- | |
563 | * | |
564 | * Tk_MeasureChars -- | |
565 | * | |
566 | * Determine the number of bytes from the string that will fit | |
567 | * in the given horizontal span. The measurement is done under the | |
568 | * assumption that Tk_DrawChars() will be used to actually display | |
569 | * the characters. | |
570 | * | |
571 | * Results: | |
572 | * The return value is the number of bytes from source that | |
573 | * fit into the span that extends from 0 to maxLength. *lengthPtr is | |
574 | * filled with the x-coordinate of the right edge of the last | |
575 | * character that did fit. | |
576 | * | |
577 | * Side effects: | |
578 | * None. | |
579 | * | |
580 | *--------------------------------------------------------------------------- | |
581 | */ | |
582 | ||
583 | int | |
584 | Tk_MeasureChars( | |
585 | Tk_Font tkfont, /* Font in which characters will be drawn. */ | |
586 | CONST char *source, /* UTF-8 string to be displayed. Need not be | |
587 | * '\0' terminated. */ | |
588 | int numBytes, /* Maximum number of bytes to consider | |
589 | * from source string. */ | |
590 | int maxLength, /* If >= 0, maxLength specifies the longest | |
591 | * permissible line length in pixels; don't | |
592 | * consider any character that would cross | |
593 | * this x-position. If < 0, then line length | |
594 | * is unbounded and the flags argument is | |
595 | * ignored. */ | |
596 | int flags, /* Various flag bits OR-ed together: | |
597 | * TK_PARTIAL_OK means include the last char | |
598 | * which only partially fit on this line. | |
599 | * TK_WHOLE_WORDS means stop on a word | |
600 | * boundary, if possible. | |
601 | * TK_AT_LEAST_ONE means return at least one | |
602 | * character even if no characters fit. */ | |
603 | int *lengthPtr) /* Filled with x-location just after the | |
604 | * terminating character. */ | |
605 | { | |
606 | HDC hdc; | |
607 | HFONT oldFont; | |
608 | WinFont *fontPtr; | |
609 | int curX, curByte; | |
610 | SubFont *lastSubFontPtr; | |
611 | ||
612 | /* | |
613 | * According to Microsoft tech support, Windows does not use kerning | |
614 | * or fractional character widths when displaying text on the screen. | |
615 | * So that means we can safely measure individual characters or spans | |
616 | * of characters and add up the widths w/o any "off-by-one-pixel" | |
617 | * errors. | |
618 | */ | |
619 | ||
620 | fontPtr = (WinFont *) tkfont; | |
621 | ||
622 | hdc = GetDC(fontPtr->hwnd); | |
623 | lastSubFontPtr = &fontPtr->subFontArray[0]; | |
624 | oldFont = SelectObject(hdc, lastSubFontPtr->hFont); | |
625 | ||
626 | if (numBytes == 0) { | |
627 | curX = 0; | |
628 | curByte = 0; | |
629 | } else if (maxLength < 0) { | |
630 | Tcl_UniChar ch; | |
631 | SIZE size; | |
632 | FontFamily *familyPtr; | |
633 | Tcl_DString runString; | |
634 | SubFont *thisSubFontPtr; | |
635 | CONST char *p, *end, *next; | |
636 | ||
637 | /* | |
638 | * A three step process: | |
639 | * 1. Find a contiguous range of characters that can all be | |
640 | * represented by a single screen font. | |
641 | * 2. Convert those chars to the encoding of that font. | |
642 | * 3. Measure converted chars. | |
643 | */ | |
644 | ||
645 | curX = 0; | |
646 | end = source + numBytes; | |
647 | for (p = source; p < end; ) { | |
648 | next = p + Tcl_UtfToUniChar(p, &ch); | |
649 | thisSubFontPtr = FindSubFontForChar(fontPtr, ch); | |
650 | if (thisSubFontPtr != lastSubFontPtr) { | |
651 | familyPtr = lastSubFontPtr->familyPtr; | |
652 | Tcl_UtfToExternalDString(familyPtr->encoding, source, | |
653 | p - source, &runString); | |
654 | (*familyPtr->getTextExtentPoint32Proc)(hdc, | |
655 | Tcl_DStringValue(&runString), | |
656 | Tcl_DStringLength(&runString) >> familyPtr->isWideFont, | |
657 | &size); | |
658 | curX += size.cx; | |
659 | Tcl_DStringFree(&runString); | |
660 | lastSubFontPtr = thisSubFontPtr; | |
661 | source = p; | |
662 | ||
663 | SelectObject(hdc, lastSubFontPtr->hFont); | |
664 | } | |
665 | p = next; | |
666 | } | |
667 | familyPtr = lastSubFontPtr->familyPtr; | |
668 | Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source, | |
669 | &runString); | |
670 | (*familyPtr->getTextExtentPoint32Proc)(hdc, | |
671 | Tcl_DStringValue(&runString), | |
672 | Tcl_DStringLength(&runString) >> familyPtr->isWideFont, | |
673 | &size); | |
674 | curX += size.cx; | |
675 | Tcl_DStringFree(&runString); | |
676 | curByte = numBytes; | |
677 | } else { | |
678 | Tcl_UniChar ch; | |
679 | SIZE size; | |
680 | char buf[16]; | |
681 | FontFamily *familyPtr; | |
682 | SubFont *thisSubFontPtr; | |
683 | CONST char *term, *end, *p, *next; | |
684 | int newX, termX, sawNonSpace, dstWrote; | |
685 | ||
686 | /* | |
687 | * How many chars will fit in the space allotted? | |
688 | * This first version may be inefficient because it measures | |
689 | * every character individually. There is a function call that | |
690 | * can measure multiple characters at once and return the | |
691 | * offset of each of them, but it only works on NT, even though | |
692 | * the documentation claims it works for 95. | |
693 | * TODO: verify that GetTextExtentExPoint is still broken in '95, and | |
694 | * possibly use it for NT anyway since it should be much faster and | |
695 | * more accurate. | |
696 | */ | |
697 | ||
698 | next = source + Tcl_UtfToUniChar(source, &ch); | |
699 | newX = curX = termX = 0; | |
700 | ||
701 | term = source; | |
702 | end = source + numBytes; | |
703 | ||
704 | sawNonSpace = (ch > 255) || !isspace(ch); | |
705 | for (p = source; ; ) { | |
706 | if (ch < BASE_CHARS) { | |
707 | newX += fontPtr->widths[ch]; | |
708 | } else { | |
709 | thisSubFontPtr = FindSubFontForChar(fontPtr, ch); | |
710 | if (thisSubFontPtr != lastSubFontPtr) { | |
711 | SelectObject(hdc, thisSubFontPtr->hFont); | |
712 | lastSubFontPtr = thisSubFontPtr; | |
713 | } | |
714 | familyPtr = lastSubFontPtr->familyPtr; | |
715 | Tcl_UtfToExternal(NULL, familyPtr->encoding, p, next - p, | |
716 | 0, NULL, buf, sizeof(buf), NULL, &dstWrote, NULL); | |
717 | (*familyPtr->getTextExtentPoint32Proc)(hdc, buf, | |
718 | dstWrote >> familyPtr->isWideFont, &size); | |
719 | newX += size.cx; | |
720 | } | |
721 | if (newX > maxLength) { | |
722 | break; | |
723 | } | |
724 | curX = newX; | |
725 | p = next; | |
726 | if (p >= end) { | |
727 | term = end; | |
728 | termX = curX; | |
729 | break; | |
730 | } | |
731 | ||
732 | next += Tcl_UtfToUniChar(next, &ch); | |
733 | if ((ch < 256) && isspace(ch)) { | |
734 | if (sawNonSpace) { | |
735 | term = p; | |
736 | termX = curX; | |
737 | sawNonSpace = 0; | |
738 | } | |
739 | } else { | |
740 | sawNonSpace = 1; | |
741 | } | |
742 | } | |
743 | ||
744 | /* | |
745 | * P points to the first character that doesn't fit in the desired | |
746 | * span. Use the flags to figure out what to return. | |
747 | */ | |
748 | ||
749 | if ((flags & TK_PARTIAL_OK) && (p < end) && (curX < maxLength)) { | |
750 | /* | |
751 | * Include the first character that didn't quite fit in the desired | |
752 | * span. The width returned will include the width of that extra | |
753 | * character. | |
754 | */ | |
755 | ||
756 | curX = newX; | |
757 | p += Tcl_UtfToUniChar(p, &ch); | |
758 | } | |
759 | if ((flags & TK_AT_LEAST_ONE) && (term == source) && (p < end)) { | |
760 | term = p; | |
761 | termX = curX; | |
762 | if (term == source) { | |
763 | term += Tcl_UtfToUniChar(term, &ch); | |
764 | termX = newX; | |
765 | } | |
766 | } else if ((p >= end) || !(flags & TK_WHOLE_WORDS)) { | |
767 | term = p; | |
768 | termX = curX; | |
769 | } | |
770 | ||
771 | curX = termX; | |
772 | curByte = term - source; | |
773 | } | |
774 | ||
775 | SelectObject(hdc, oldFont); | |
776 | ReleaseDC(fontPtr->hwnd, hdc); | |
777 | ||
778 | *lengthPtr = curX; | |
779 | return curByte; | |
780 | } | |
781 | ||
782 | /* | |
783 | *--------------------------------------------------------------------------- | |
784 | * | |
785 | * Tk_DrawChars -- | |
786 | * | |
787 | * Draw a string of characters on the screen. | |
788 | * | |
789 | * Results: | |
790 | * None. | |
791 | * | |
792 | * Side effects: | |
793 | * Information gets drawn on the screen. | |
794 | * | |
795 | *--------------------------------------------------------------------------- | |
796 | */ | |
797 | ||
798 | void | |
799 | Tk_DrawChars( | |
800 | Display *display, /* Display on which to draw. */ | |
801 | Drawable drawable, /* Window or pixmap in which to draw. */ | |
802 | GC gc, /* Graphics context for drawing characters. */ | |
803 | Tk_Font tkfont, /* Font in which characters will be drawn; | |
804 | * must be the same as font used in GC. */ | |
805 | CONST char *source, /* UTF-8 string to be displayed. Need not be | |
806 | * '\0' terminated. All Tk meta-characters | |
807 | * (tabs, control characters, and newlines) | |
808 | * should be stripped out of the string that | |
809 | * is passed to this function. If they are | |
810 | * not stripped out, they will be displayed as | |
811 | * regular printing characters. */ | |
812 | int numBytes, /* Number of bytes in string. */ | |
813 | int x, int y) /* Coordinates at which to place origin of | |
814 | * string when drawing. */ | |
815 | { | |
816 | HDC dc; | |
817 | WinFont *fontPtr; | |
818 | TkWinDCState state; | |
819 | ||
820 | fontPtr = (WinFont *) gc->font; | |
821 | display->request++; | |
822 | ||
823 | if (drawable == None) { | |
824 | return; | |
825 | } | |
826 | ||
827 | dc = TkWinGetDrawableDC(display, drawable, &state); | |
828 | ||
829 | SetROP2(dc, tkpWinRopModes[gc->function]); | |
830 | ||
831 | if ((gc->fill_style == FillStippled | |
832 | || gc->fill_style == FillOpaqueStippled) | |
833 | && gc->stipple != None) { | |
834 | TkWinDrawable *twdPtr = (TkWinDrawable *)gc->stipple; | |
835 | HBRUSH oldBrush, stipple; | |
836 | HBITMAP oldBitmap, bitmap; | |
837 | HDC dcMem; | |
838 | TEXTMETRIC tm; | |
839 | SIZE size; | |
840 | ||
841 | if (twdPtr->type != TWD_BITMAP) { | |
842 | panic("unexpected drawable type in stipple"); | |
843 | } | |
844 | ||
845 | /* | |
846 | * Select stipple pattern into destination dc. | |
847 | */ | |
848 | ||
849 | dcMem = CreateCompatibleDC(dc); | |
850 | ||
851 | stipple = CreatePatternBrush(twdPtr->bitmap.handle); | |
852 | SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL); | |
853 | oldBrush = SelectObject(dc, stipple); | |
854 | ||
855 | SetTextAlign(dcMem, TA_LEFT | TA_BASELINE); | |
856 | SetTextColor(dcMem, gc->foreground); | |
857 | SetBkMode(dcMem, TRANSPARENT); | |
858 | SetBkColor(dcMem, RGB(0, 0, 0)); | |
859 | ||
860 | /* | |
861 | * Compute the bounding box and create a compatible bitmap. | |
862 | */ | |
863 | ||
864 | GetTextExtentPoint(dcMem, source, numBytes, &size); | |
865 | GetTextMetrics(dcMem, &tm); | |
866 | size.cx -= tm.tmOverhang; | |
867 | bitmap = CreateCompatibleBitmap(dc, size.cx, size.cy); | |
868 | oldBitmap = SelectObject(dcMem, bitmap); | |
869 | ||
870 | /* | |
871 | * The following code is tricky because fonts are rendered in multiple | |
872 | * colors. First we draw onto a black background and copy the white | |
873 | * bits. Then we draw onto a white background and copy the black bits. | |
874 | * Both the foreground and background bits of the font are ANDed with | |
875 | * the stipple pattern as they are copied. | |
876 | */ | |
877 | ||
878 | PatBlt(dcMem, 0, 0, size.cx, size.cy, BLACKNESS); | |
879 | MultiFontTextOut(dc, fontPtr, source, numBytes, x, y); | |
880 | BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem, | |
881 | 0, 0, 0xEA02E9); | |
882 | PatBlt(dcMem, 0, 0, size.cx, size.cy, WHITENESS); | |
883 | MultiFontTextOut(dc, fontPtr, source, numBytes, x, y); | |
884 | BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem, | |
885 | 0, 0, 0x8A0E06); | |
886 | ||
887 | /* | |
888 | * Destroy the temporary bitmap and restore the device context. | |
889 | */ | |
890 | ||
891 | SelectObject(dcMem, oldBitmap); | |
892 | DeleteObject(bitmap); | |
893 | DeleteDC(dcMem); | |
894 | SelectObject(dc, oldBrush); | |
895 | DeleteObject(stipple); | |
896 | } else { | |
897 | SetTextAlign(dc, TA_LEFT | TA_BASELINE); | |
898 | SetTextColor(dc, gc->foreground); | |
899 | SetBkMode(dc, TRANSPARENT); | |
900 | MultiFontTextOut(dc, fontPtr, source, numBytes, x, y); | |
901 | } | |
902 | TkWinReleaseDrawableDC(drawable, dc, &state); | |
903 | } | |
904 | ||
905 | /* | |
906 | *------------------------------------------------------------------------- | |
907 | * | |
908 | * MultiFontTextOut -- | |
909 | * | |
910 | * Helper function for Tk_DrawChars. Draws characters, using the | |
911 | * various screen fonts in fontPtr to draw multilingual characters. | |
912 | * Note: No bidirectional support. | |
913 | * | |
914 | * Results: | |
915 | * None. | |
916 | * | |
917 | * Side effects: | |
918 | * Information gets drawn on the screen. | |
919 | * Contents of fontPtr may be modified if more subfonts were loaded | |
920 | * in order to draw all the multilingual characters in the given | |
921 | * string. | |
922 | * | |
923 | *------------------------------------------------------------------------- | |
924 | */ | |
925 | ||
926 | static void | |
927 | MultiFontTextOut( | |
928 | HDC hdc, /* HDC to draw into. */ | |
929 | WinFont *fontPtr, /* Contains set of fonts to use when drawing | |
930 | * following string. */ | |
931 | CONST char *source, /* Potentially multilingual UTF-8 string. */ | |
932 | int numBytes, /* Length of string in bytes. */ | |
933 | int x, int y) /* Coordinates at which to place origin * | |
934 | * of string when drawing. */ | |
935 | { | |
936 | Tcl_UniChar ch; | |
937 | SIZE size; | |
938 | HFONT oldFont; | |
939 | FontFamily *familyPtr; | |
940 | Tcl_DString runString; | |
941 | CONST char *p, *end, *next; | |
942 | SubFont *lastSubFontPtr, *thisSubFontPtr; | |
943 | ||
944 | lastSubFontPtr = &fontPtr->subFontArray[0]; | |
945 | oldFont = SelectObject(hdc, lastSubFontPtr->hFont); | |
946 | ||
947 | end = source + numBytes; | |
948 | for (p = source; p < end; ) { | |
949 | next = p + Tcl_UtfToUniChar(p, &ch); | |
950 | thisSubFontPtr = FindSubFontForChar(fontPtr, ch); | |
951 | if (thisSubFontPtr != lastSubFontPtr) { | |
952 | if (p > source) { | |
953 | familyPtr = lastSubFontPtr->familyPtr; | |
954 | Tcl_UtfToExternalDString(familyPtr->encoding, source, | |
955 | p - source, &runString); | |
956 | (*familyPtr->textOutProc)(hdc, x, y, | |
957 | Tcl_DStringValue(&runString), | |
958 | Tcl_DStringLength(&runString) >> familyPtr->isWideFont); | |
959 | (*familyPtr->getTextExtentPoint32Proc)(hdc, | |
960 | Tcl_DStringValue(&runString), | |
961 | Tcl_DStringLength(&runString) >> familyPtr->isWideFont, | |
962 | &size); | |
963 | x += size.cx; | |
964 | Tcl_DStringFree(&runString); | |
965 | } | |
966 | lastSubFontPtr = thisSubFontPtr; | |
967 | source = p; | |
968 | SelectObject(hdc, lastSubFontPtr->hFont); | |
969 | } | |
970 | p = next; | |
971 | } | |
972 | if (p > source) { | |
973 | familyPtr = lastSubFontPtr->familyPtr; | |
974 | Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source, | |
975 | &runString); | |
976 | (*familyPtr->textOutProc)(hdc, x, y, Tcl_DStringValue(&runString), | |
977 | Tcl_DStringLength(&runString) >> familyPtr->isWideFont); | |
978 | Tcl_DStringFree(&runString); | |
979 | } | |
980 | SelectObject(hdc, oldFont); | |
981 | } | |
982 | ||
983 | /* | |
984 | *--------------------------------------------------------------------------- | |
985 | * | |
986 | * InitFont -- | |
987 | * | |
988 | * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes(). | |
989 | * Initializes the memory for a new WinFont that wraps the | |
990 | * platform-specific data. | |
991 | * | |
992 | * The caller is responsible for initializing the fields of the | |
993 | * WinFont that are used exclusively by the generic TkFont code, and | |
994 | * for releasing those fields before calling TkpDeleteFont(). | |
995 | * | |
996 | * Results: | |
997 | * Fills the WinFont structure. | |
998 | * | |
999 | * Side effects: | |
1000 | * Memory allocated. | |
1001 | * | |
1002 | *--------------------------------------------------------------------------- | |
1003 | */ | |
1004 | ||
1005 | static void | |
1006 | InitFont( | |
1007 | Tk_Window tkwin, /* Main window of interp in which font will | |
1008 | * be used, for getting HDC. */ | |
1009 | HFONT hFont, /* Windows token for font. */ | |
1010 | int overstrike, /* The overstrike attribute of logfont used | |
1011 | * to allocate this font. For some reason, | |
1012 | * the TEXTMETRICs may contain incorrect info | |
1013 | * in the tmStruckOut field. */ | |
1014 | WinFont *fontPtr) /* Filled with information constructed from | |
1015 | * the above arguments. */ | |
1016 | { | |
1017 | HDC hdc; | |
1018 | HWND hwnd; | |
1019 | HFONT oldFont; | |
1020 | TEXTMETRIC tm; | |
1021 | Window window; | |
1022 | TkFontMetrics *fmPtr; | |
1023 | Tcl_Encoding encoding; | |
1024 | Tcl_DString faceString; | |
1025 | TkFontAttributes *faPtr; | |
1026 | char buf[LF_FACESIZE * sizeof(WCHAR)]; | |
1027 | ||
1028 | window = Tk_WindowId(tkwin); | |
1029 | hwnd = (window == None) ? NULL : TkWinGetHWND(window); | |
1030 | hdc = GetDC(hwnd); | |
1031 | oldFont = SelectObject(hdc, hFont); | |
1032 | ||
1033 | GetTextMetrics(hdc, &tm); | |
1034 | ||
1035 | /* | |
1036 | * On any version NT, there may fonts with international names. | |
1037 | * Use the NT-only Unicode version of GetTextFace to get the font's | |
1038 | * name. If we used the ANSI version on a non-internationalized | |
1039 | * version of NT, we would get a font name with '?' replacing all | |
1040 | * the international characters. | |
1041 | * | |
1042 | * On a non-internationalized verson of 95, fonts with international | |
1043 | * names are not allowed, so the ANSI version of GetTextFace will work. | |
1044 | * On an internationalized version of 95, there may be fonts with | |
1045 | * international names; the ANSI version will work, fetching the | |
1046 | * name in the international system code page. Can't use the Unicode | |
1047 | * version of GetTextFace because it only exists under NT. | |
1048 | */ | |
1049 | ||
1050 | if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { | |
1051 | GetTextFaceW(hdc, LF_FACESIZE, (WCHAR *) buf); | |
1052 | } else { | |
1053 | GetTextFaceA(hdc, LF_FACESIZE, (char *) buf); | |
1054 | } | |
1055 | Tcl_ExternalToUtfDString(systemEncoding, buf, -1, &faceString); | |
1056 | ||
1057 | fontPtr->font.fid = (Font) fontPtr; | |
1058 | ||
1059 | faPtr = &fontPtr->font.fa; | |
1060 | faPtr->family = Tk_GetUid(Tcl_DStringValue(&faceString)); | |
1061 | faPtr->size = TkFontGetPoints(tkwin, -(tm.tmHeight - tm.tmInternalLeading)); | |
1062 | faPtr->weight = (tm.tmWeight > FW_MEDIUM) ? TK_FW_BOLD : TK_FW_NORMAL; | |
1063 | faPtr->slant = (tm.tmItalic != 0) ? TK_FS_ITALIC : TK_FS_ROMAN; | |
1064 | faPtr->underline = (tm.tmUnderlined != 0) ? 1 : 0; | |
1065 | faPtr->overstrike = overstrike; | |
1066 | ||
1067 | fmPtr = &fontPtr->font.fm; | |
1068 | fmPtr->ascent = tm.tmAscent; | |
1069 | fmPtr->descent = tm.tmDescent; | |
1070 | fmPtr->maxWidth = tm.tmMaxCharWidth; | |
1071 | fmPtr->fixed = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH); | |
1072 | ||
1073 | fontPtr->hwnd = hwnd; | |
1074 | fontPtr->pixelSize = tm.tmHeight - tm.tmInternalLeading; | |
1075 | ||
1076 | fontPtr->numSubFonts = 1; | |
1077 | fontPtr->subFontArray = fontPtr->staticSubFonts; | |
1078 | InitSubFont(hdc, hFont, 1, &fontPtr->subFontArray[0]); | |
1079 | ||
1080 | encoding = fontPtr->subFontArray[0].familyPtr->encoding; | |
1081 | if (encoding == unicodeEncoding) { | |
1082 | GetCharWidthW(hdc, 0, BASE_CHARS - 1, fontPtr->widths); | |
1083 | } else { | |
1084 | GetCharWidthA(hdc, 0, BASE_CHARS - 1, fontPtr->widths); | |
1085 | } | |
1086 | Tcl_DStringFree(&faceString); | |
1087 | ||
1088 | SelectObject(hdc, oldFont); | |
1089 | ReleaseDC(hwnd, hdc); | |
1090 | } | |
1091 | ||
1092 | /* | |
1093 | *------------------------------------------------------------------------- | |
1094 | * | |
1095 | * ReleaseFont -- | |
1096 | * | |
1097 | * Called to release the windows-specific contents of a TkFont. | |
1098 | * The caller is responsible for freeing the memory used by the | |
1099 | * font itself. | |
1100 | * | |
1101 | * Results: | |
1102 | * None. | |
1103 | * | |
1104 | * Side effects: | |
1105 | * Memory is freed. | |
1106 | * | |
1107 | *--------------------------------------------------------------------------- | |
1108 | */ | |
1109 | ||
1110 | static void | |
1111 | ReleaseFont( | |
1112 | WinFont *fontPtr) /* The font to delete. */ | |
1113 | { | |
1114 | int i; | |
1115 | ||
1116 | for (i = 0; i < fontPtr->numSubFonts; i++) { | |
1117 | ReleaseSubFont(&fontPtr->subFontArray[i]); | |
1118 | } | |
1119 | if (fontPtr->subFontArray != fontPtr->staticSubFonts) { | |
1120 | ckfree((char *) fontPtr->subFontArray); | |
1121 | } | |
1122 | } | |
1123 | ||
1124 | /* | |
1125 | *------------------------------------------------------------------------- | |
1126 | * | |
1127 | * InitSubFont -- | |
1128 | * | |
1129 | * Wrap a screen font and load the FontFamily that represents | |
1130 | * it. Used to prepare a SubFont so that characters can be mapped | |
1131 | * from UTF-8 to the charset of the font. | |
1132 | * | |
1133 | * Results: | |
1134 | * The subFontPtr is filled with information about the font. | |
1135 | * | |
1136 | * Side effects: | |
1137 | * None. | |
1138 | * | |
1139 | *------------------------------------------------------------------------- | |
1140 | */ | |
1141 | ||
1142 | static void | |
1143 | InitSubFont( | |
1144 | HDC hdc, /* HDC in which font can be selected. */ | |
1145 | HFONT hFont, /* The screen font. */ | |
1146 | int base, /* Non-zero if this SubFont is being used | |
1147 | * as the base font for a font object. */ | |
1148 | SubFont *subFontPtr) /* Filled with SubFont constructed from | |
1149 | * above attributes. */ | |
1150 | { | |
1151 | subFontPtr->hFont = hFont; | |
1152 | subFontPtr->familyPtr = AllocFontFamily(hdc, hFont, base); | |
1153 | subFontPtr->fontMap = subFontPtr->familyPtr->fontMap; | |
1154 | } | |
1155 | ||
1156 | /* | |
1157 | *------------------------------------------------------------------------- | |
1158 | * | |
1159 | * ReleaseSubFont -- | |
1160 | * | |
1161 | * Called to release the contents of a SubFont. The caller is | |
1162 | * responsible for freeing the memory used by the SubFont itself. | |
1163 | * | |
1164 | * Results: | |
1165 | * None. | |
1166 | * | |
1167 | * Side effects: | |
1168 | * Memory and resources are freed. | |
1169 | * | |
1170 | *--------------------------------------------------------------------------- | |
1171 | */ | |
1172 | ||
1173 | static void | |
1174 | ReleaseSubFont( | |
1175 | SubFont *subFontPtr) /* The SubFont to delete. */ | |
1176 | { | |
1177 | DeleteObject(subFontPtr->hFont); | |
1178 | FreeFontFamily(subFontPtr->familyPtr); | |
1179 | } | |
1180 | ||
1181 | /* | |
1182 | *------------------------------------------------------------------------- | |
1183 | * | |
1184 | * AllocFontFamily -- | |
1185 | * | |
1186 | * Find the FontFamily structure associated with the given font | |
1187 | * name. The information should be stored by the caller in a | |
1188 | * SubFont and used when determining if that SubFont supports a | |
1189 | * character. | |
1190 | * | |
1191 | * Cannot use the string name used to construct the font as the | |
1192 | * key, because the capitalization may not be canonical. Therefore | |
1193 | * use the face name actually retrieved from the font metrics as | |
1194 | * the key. | |
1195 | * | |
1196 | * Results: | |
1197 | * A pointer to a FontFamily. The reference count in the FontFamily | |
1198 | * is automatically incremented. When the SubFont is released, the | |
1199 | * reference count is decremented. When no SubFont is using this | |
1200 | * FontFamily, it may be deleted. | |
1201 | * | |
1202 | * Side effects: | |
1203 | * A new FontFamily structure will be allocated if this font family | |
1204 | * has not been seen. TrueType character existence metrics are | |
1205 | * loaded into the FontFamily structure. | |
1206 | * | |
1207 | *------------------------------------------------------------------------- | |
1208 | */ | |
1209 | ||
1210 | static FontFamily * | |
1211 | AllocFontFamily( | |
1212 | HDC hdc, /* HDC in which font can be selected. */ | |
1213 | HFONT hFont, /* Screen font whose FontFamily is to be | |
1214 | * returned. */ | |
1215 | int base) /* Non-zero if this font family is to be | |
1216 | * used in the base font of a font object. */ | |
1217 | { | |
1218 | Tk_Uid faceName; | |
1219 | FontFamily *familyPtr; | |
1220 | Tcl_DString faceString; | |
1221 | Tcl_Encoding encoding; | |
1222 | char buf[LF_FACESIZE * sizeof(WCHAR)]; | |
1223 | ThreadSpecificData *tsdPtr = (ThreadSpecificData *) | |
1224 | Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); | |
1225 | ||
1226 | hFont = SelectObject(hdc, hFont); | |
1227 | if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { | |
1228 | GetTextFaceW(hdc, LF_FACESIZE, (WCHAR *) buf); | |
1229 | } else { | |
1230 | GetTextFaceA(hdc, LF_FACESIZE, (char *) buf); | |
1231 | } | |
1232 | Tcl_ExternalToUtfDString(systemEncoding, buf, -1, &faceString); | |
1233 | faceName = Tk_GetUid(Tcl_DStringValue(&faceString)); | |
1234 | Tcl_DStringFree(&faceString); | |
1235 | hFont = SelectObject(hdc, hFont); | |
1236 | ||
1237 | familyPtr = tsdPtr->fontFamilyList; | |
1238 | for ( ; familyPtr != NULL; familyPtr = familyPtr->nextPtr) { | |
1239 | if (familyPtr->faceName == faceName) { | |
1240 | familyPtr->refCount++; | |
1241 | return familyPtr; | |
1242 | } | |
1243 | } | |
1244 | ||
1245 | familyPtr = (FontFamily *) ckalloc(sizeof(FontFamily)); | |
1246 | memset(familyPtr, 0, sizeof(FontFamily)); | |
1247 | familyPtr->nextPtr = tsdPtr->fontFamilyList; | |
1248 | tsdPtr->fontFamilyList = familyPtr; | |
1249 | ||
1250 | /* | |
1251 | * Set key for this FontFamily. | |
1252 | */ | |
1253 | ||
1254 | familyPtr->faceName = faceName; | |
1255 | ||
1256 | /* | |
1257 | * An initial refCount of 2 means that FontFamily information will | |
1258 | * persist even when the SubFont that loaded the FontFamily is released. | |
1259 | * Change it to 1 to cause FontFamilies to be unloaded when not in use. | |
1260 | */ | |
1261 | ||
1262 | familyPtr->refCount = 2; | |
1263 | ||
1264 | familyPtr->segCount = LoadFontRanges(hdc, hFont, &familyPtr->startCount, | |
1265 | &familyPtr->endCount, &familyPtr->isSymbolFont); | |
1266 | ||
1267 | encoding = NULL; | |
1268 | if (familyPtr->isSymbolFont != 0) { | |
1269 | /* | |
1270 | * Symbol fonts are handled specially. For instance, Unicode 0393 | |
1271 | * (GREEK CAPITAL GAMMA) must be mapped to Symbol character 0047 | |
1272 | * (GREEK CAPITAL GAMMA), because the Symbol font doesn't have a | |
1273 | * GREEK CAPITAL GAMMA at location 0393. If Tk interpreted the | |
1274 | * Symbol font using the Unicode encoding, it would decide that | |
1275 | * the Symbol font has no GREEK CAPITAL GAMMA, because the Symbol | |
1276 | * encoding (of course) reports that character 0393 doesn't exist. | |
1277 | * | |
1278 | * With non-symbol Windows fonts, such as Times New Roman, if the | |
1279 | * font has a GREEK CAPITAL GAMMA, it will be found in the correct | |
1280 | * Unicode location (0393); the GREEK CAPITAL GAMMA will not be off | |
1281 | * hiding at some other location. | |
1282 | */ | |
1283 | ||
1284 | encoding = Tcl_GetEncoding(NULL, faceName); | |
1285 | } | |
1286 | ||
1287 | if (encoding == NULL) { | |
1288 | encoding = Tcl_GetEncoding(NULL, "unicode"); | |
1289 | familyPtr->textOutProc = | |
1290 | (BOOL (WINAPI *)(HDC, int, int, TCHAR *, int)) TextOutW; | |
1291 | familyPtr->getTextExtentPoint32Proc = | |
1292 | (BOOL (WINAPI *)(HDC, TCHAR *, int, LPSIZE)) GetTextExtentPoint32W; | |
1293 | familyPtr->isWideFont = 1; | |
1294 | } else { | |
1295 | familyPtr->textOutProc = | |
1296 | (BOOL (WINAPI *)(HDC, int, int, TCHAR *, int)) TextOutA; | |
1297 | familyPtr->getTextExtentPoint32Proc = | |
1298 | (BOOL (WINAPI *)(HDC, TCHAR *, int, LPSIZE)) GetTextExtentPoint32A; | |
1299 | familyPtr->isWideFont = 0; | |
1300 | } | |
1301 | ||
1302 | familyPtr->encoding = encoding; | |
1303 | ||
1304 | return familyPtr; | |
1305 | } | |
1306 | ||
1307 | /* | |
1308 | *------------------------------------------------------------------------- | |
1309 | * | |
1310 | * FreeFontFamily -- | |
1311 | * | |
1312 | * Called to free a FontFamily when the SubFont is finished using it. | |
1313 | * Frees the contents of the FontFamily and the memory used by the | |
1314 | * FontFamily itself. | |
1315 | * | |
1316 | * Results: | |
1317 | * None. | |
1318 | * | |
1319 | * Side effects: | |
1320 | * None. | |
1321 | * | |
1322 | *------------------------------------------------------------------------- | |
1323 | */ | |
1324 | ||
1325 | static void | |
1326 | FreeFontFamily( | |
1327 | FontFamily *familyPtr) /* The FontFamily to delete. */ | |
1328 | { | |
1329 | int i; | |
1330 | FontFamily **familyPtrPtr; | |
1331 | ThreadSpecificData *tsdPtr = (ThreadSpecificData *) | |
1332 | Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); | |
1333 | ||
1334 | if (familyPtr == NULL) { | |
1335 | return; | |
1336 | } | |
1337 | familyPtr->refCount--; | |
1338 | if (familyPtr->refCount > 0) { | |
1339 | return; | |
1340 | } | |
1341 | for (i = 0; i < FONTMAP_PAGES; i++) { | |
1342 | if (familyPtr->fontMap[i] != NULL) { | |
1343 | ckfree(familyPtr->fontMap[i]); | |
1344 | } | |
1345 | } | |
1346 | if (familyPtr->startCount != NULL) { | |
1347 | ckfree((char *) familyPtr->startCount); | |
1348 | } | |
1349 | if (familyPtr->endCount != NULL) { | |
1350 | ckfree((char *) familyPtr->endCount); | |
1351 | } | |
1352 | if (familyPtr->encoding != unicodeEncoding) { | |
1353 | Tcl_FreeEncoding(familyPtr->encoding); | |
1354 | } | |
1355 | ||
1356 | /* | |
1357 | * Delete from list. | |
1358 | */ | |
1359 | ||
1360 | for (familyPtrPtr = &tsdPtr->fontFamilyList; ; ) { | |
1361 | if (*familyPtrPtr == familyPtr) { | |
1362 | *familyPtrPtr = familyPtr->nextPtr; | |
1363 | break; | |
1364 | } | |
1365 | familyPtrPtr = &(*familyPtrPtr)->nextPtr; | |
1366 | } | |
1367 | ||
1368 | ckfree((char *) familyPtr); | |
1369 | } | |
1370 | ||
1371 | /* | |
1372 | *------------------------------------------------------------------------- | |
1373 | * | |
1374 | * FindSubFontForChar -- | |
1375 | * | |
1376 | * Determine which screen font is necessary to use to display the | |
1377 | * given character. If the font object does not have a screen font | |
1378 | * that can display the character, another screen font may be loaded | |
1379 | * into the font object, following a set of preferred fallback rules. | |
1380 | * | |
1381 | * Results: | |
1382 | * The return value is the SubFont to use to display the given | |
1383 | * character. | |
1384 | * | |
1385 | * Side effects: | |
1386 | * The contents of fontPtr are modified to cache the results | |
1387 | * of the lookup and remember any SubFonts that were dynamically | |
1388 | * loaded. | |
1389 | * | |
1390 | *------------------------------------------------------------------------- | |
1391 | */ | |
1392 | ||
1393 | static SubFont * | |
1394 | FindSubFontForChar( | |
1395 | WinFont *fontPtr, /* The font object with which the character | |
1396 | * will be displayed. */ | |
1397 | int ch) /* The Unicode character to be displayed. */ | |
1398 | { | |
1399 | HDC hdc; | |
1400 | int i, j, k; | |
1401 | CanUse canUse; | |
1402 | char **aliases, **anyFallbacks; | |
1403 | char ***fontFallbacks; | |
1404 | char *fallbackName; | |
1405 | SubFont *subFontPtr; | |
1406 | Tcl_DString ds; | |
1407 | ||
1408 | if (ch < BASE_CHARS) { | |
1409 | return &fontPtr->subFontArray[0]; | |
1410 | } | |
1411 | ||
1412 | for (i = 0; i < fontPtr->numSubFonts; i++) { | |
1413 | if (FontMapLookup(&fontPtr->subFontArray[i], ch)) { | |
1414 | return &fontPtr->subFontArray[i]; | |
1415 | } | |
1416 | } | |
1417 | ||
1418 | /* | |
1419 | * Keep track of all face names that we check, so we don't check some | |
1420 | * name multiple times if it can be reached by multiple paths. | |
1421 | */ | |
1422 | ||
1423 | Tcl_DStringInit(&ds); | |
1424 | hdc = GetDC(fontPtr->hwnd); | |
1425 | ||
1426 | aliases = TkFontGetAliasList(fontPtr->font.fa.family); | |
1427 | ||
1428 | fontFallbacks = TkFontGetFallbacks(); | |
1429 | for (i = 0; fontFallbacks[i] != NULL; i++) { | |
1430 | for (j = 0; fontFallbacks[i][j] != NULL; j++) { | |
1431 | fallbackName = fontFallbacks[i][j]; | |
1432 | if (strcasecmp(fallbackName, fontPtr->font.fa.family) == 0) { | |
1433 | /* | |
1434 | * If the base font has a fallback... | |
1435 | */ | |
1436 | ||
1437 | goto tryfallbacks; | |
1438 | } else if (aliases != NULL) { | |
1439 | /* | |
1440 | * Or if an alias for the base font has a fallback... | |
1441 | */ | |
1442 | ||
1443 | for (k = 0; aliases[k] != NULL; k++) { | |
1444 | if (strcasecmp(aliases[k], fallbackName) == 0) { | |
1445 | goto tryfallbacks; | |
1446 | } | |
1447 | } | |
1448 | } | |
1449 | } | |
1450 | continue; | |
1451 | ||
1452 | /* | |
1453 | * ...then see if we can use one of the fallbacks, or an | |
1454 | * alias for one of the fallbacks. | |
1455 | */ | |
1456 | ||
1457 | tryfallbacks: | |
1458 | for (j = 0; fontFallbacks[i][j] != NULL; j++) { | |
1459 | fallbackName = fontFallbacks[i][j]; | |
1460 | subFontPtr = CanUseFallbackWithAliases(hdc, fontPtr, fallbackName, | |
1461 | ch, &ds); | |
1462 | if (subFontPtr != NULL) { | |
1463 | goto end; | |
1464 | } | |
1465 | } | |
1466 | } | |
1467 | ||
1468 | /* | |
1469 | * See if we can use something from the global fallback list. | |
1470 | */ | |
1471 | ||
1472 | anyFallbacks = TkFontGetGlobalClass(); | |
1473 | for (i = 0; anyFallbacks[i] != NULL; i++) { | |
1474 | fallbackName = anyFallbacks[i]; | |
1475 | subFontPtr = CanUseFallbackWithAliases(hdc, fontPtr, fallbackName, | |
1476 | ch, &ds); | |
1477 | if (subFontPtr != NULL) { | |
1478 | goto end; | |
1479 | } | |
1480 | } | |
1481 | ||
1482 | /* | |
1483 | * Try all face names available in the whole system until we | |
1484 | * find one that can be used. | |
1485 | */ | |
1486 | ||
1487 | canUse.hdc = hdc; | |
1488 | canUse.fontPtr = fontPtr; | |
1489 | canUse.nameTriedPtr = &ds; | |
1490 | canUse.ch = ch; | |
1491 | canUse.subFontPtr = NULL; | |
1492 | if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { | |
1493 | EnumFontFamiliesW(hdc, NULL, (FONTENUMPROCW) WinFontCanUseProc, | |
1494 | (LPARAM) &canUse); | |
1495 | } else { | |
1496 | EnumFontFamiliesA(hdc, NULL, (FONTENUMPROCA) WinFontCanUseProc, | |
1497 | (LPARAM) &canUse); | |
1498 | } | |
1499 | subFontPtr = canUse.subFontPtr; | |
1500 | ||
1501 | end: | |
1502 | Tcl_DStringFree(&ds); | |
1503 | ||
1504 | if (subFontPtr == NULL) { | |
1505 | /* | |
1506 | * No font can display this character. We will use the base font | |
1507 | * and have it display the "unknown" character. | |
1508 | */ | |
1509 | ||
1510 | subFontPtr = &fontPtr->subFontArray[0]; | |
1511 | FontMapInsert(subFontPtr, ch); | |
1512 | } | |
1513 | ReleaseDC(fontPtr->hwnd, hdc); | |
1514 | return subFontPtr; | |
1515 | } | |
1516 | ||
1517 | static int CALLBACK | |
1518 | WinFontCanUseProc( | |
1519 | ENUMLOGFONT *lfPtr, /* Logical-font data. */ | |
1520 | NEWTEXTMETRIC *tmPtr, /* Physical-font data (not used). */ | |
1521 | int fontType, /* Type of font (not used). */ | |
1522 | LPARAM lParam) /* Result object to hold result. */ | |
1523 | { | |
1524 | int ch; | |
1525 | HDC hdc; | |
1526 | WinFont *fontPtr; | |
1527 | CanUse *canUsePtr; | |
1528 | char *fallbackName; | |
1529 | SubFont *subFontPtr; | |
1530 | Tcl_DString faceString; | |
1531 | Tcl_DString *nameTriedPtr; | |
1532 | ||
1533 | canUsePtr = (CanUse *) lParam; | |
1534 | ch = canUsePtr->ch; | |
1535 | hdc = canUsePtr->hdc; | |
1536 | fontPtr = canUsePtr->fontPtr; | |
1537 | nameTriedPtr = canUsePtr->nameTriedPtr; | |
1538 | ||
1539 | fallbackName = lfPtr->elfLogFont.lfFaceName; | |
1540 | Tcl_ExternalToUtfDString(systemEncoding, fallbackName, -1, &faceString); | |
1541 | fallbackName = Tcl_DStringValue(&faceString); | |
1542 | ||
1543 | if (SeenName(fallbackName, nameTriedPtr) == 0) { | |
1544 | subFontPtr = CanUseFallback(hdc, fontPtr, fallbackName, ch); | |
1545 | if (subFontPtr != NULL) { | |
1546 | canUsePtr->subFontPtr = subFontPtr; | |
1547 | Tcl_DStringFree(&faceString); | |
1548 | return 0; | |
1549 | } | |
1550 | } | |
1551 | Tcl_DStringFree(&faceString); | |
1552 | return 1; | |
1553 | } | |
1554 | ||
1555 | /* | |
1556 | *------------------------------------------------------------------------- | |
1557 | * | |
1558 | * FontMapLookup -- | |
1559 | * | |
1560 | * See if the screen font can display the given character. | |
1561 | * | |
1562 | * Results: | |
1563 | * The return value is 0 if the screen font cannot display the | |
1564 | * character, non-zero otherwise. | |
1565 | * | |
1566 | * Side effects: | |
1567 | * New pages are added to the font mapping cache whenever the | |
1568 | * character belongs to a page that hasn't been seen before. | |
1569 | * When a page is loaded, information about all the characters on | |
1570 | * that page is stored, not just for the single character in | |
1571 | * question. | |
1572 | * | |
1573 | *------------------------------------------------------------------------- | |
1574 | */ | |
1575 | ||
1576 | static int | |
1577 | FontMapLookup( | |
1578 | SubFont *subFontPtr, /* Contains font mapping cache to be queried | |
1579 | * and possibly updated. */ | |
1580 | int ch) /* Character to be tested. */ | |
1581 | { | |
1582 | int row, bitOffset; | |
1583 | ||
1584 | row = ch >> FONTMAP_SHIFT; | |
1585 | if (subFontPtr->fontMap[row] == NULL) { | |
1586 | FontMapLoadPage(subFontPtr, row); | |
1587 | } | |
1588 | bitOffset = ch & (FONTMAP_BITSPERPAGE - 1); | |
1589 | return (subFontPtr->fontMap[row][bitOffset >> 3] >> (bitOffset & 7)) & 1; | |
1590 | } | |
1591 | ||
1592 | /* | |
1593 | *------------------------------------------------------------------------- | |
1594 | * | |
1595 | * FontMapInsert -- | |
1596 | * | |
1597 | * Tell the font mapping cache that the given screen font should be | |
1598 | * used to display the specified character. This is called when no | |
1599 | * font on the system can be be found that can display that | |
1600 | * character; we lie to the font and tell it that it can display | |
1601 | * the character, otherwise we would end up re-searching the entire | |
1602 | * fallback hierarchy every time that character was seen. | |
1603 | * | |
1604 | * Results: | |
1605 | * None. | |
1606 | * | |
1607 | * Side effects: | |
1608 | * New pages are added to the font mapping cache whenever the | |
1609 | * character belongs to a page that hasn't been seen before. | |
1610 | * When a page is loaded, information about all the characters on | |
1611 | * that page is stored, not just for the single character in | |
1612 | * question. | |
1613 | * | |
1614 | *------------------------------------------------------------------------- | |
1615 | */ | |
1616 | ||
1617 | static void | |
1618 | FontMapInsert( | |
1619 | SubFont *subFontPtr, /* Contains font mapping cache to be | |
1620 | * updated. */ | |
1621 | int ch) /* Character to be added to cache. */ | |
1622 | { | |
1623 | int row, bitOffset; | |
1624 | ||
1625 | row = ch >> FONTMAP_SHIFT; | |
1626 | if (subFontPtr->fontMap[row] == NULL) { | |
1627 | FontMapLoadPage(subFontPtr, row); | |
1628 | } | |
1629 | bitOffset = ch & (FONTMAP_BITSPERPAGE - 1); | |
1630 | subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7); | |
1631 | } | |
1632 | ||
1633 | /* | |
1634 | *------------------------------------------------------------------------- | |
1635 | * | |
1636 | * FontMapLoadPage -- | |
1637 | * | |
1638 | * Load information about all the characters on a given page. | |
1639 | * This information consists of one bit per character that indicates | |
1640 | * whether the associated HFONT can (1) or cannot (0) display the | |
1641 | * characters on the page. | |
1642 | * | |
1643 | * Results: | |
1644 | * None. | |
1645 | * | |
1646 | * Side effects: | |
1647 | * Mempry allocated. | |
1648 | * | |
1649 | *------------------------------------------------------------------------- | |
1650 | */ | |
1651 | static void | |
1652 | FontMapLoadPage( | |
1653 | SubFont *subFontPtr, /* Contains font mapping cache to be | |
1654 | * updated. */ | |
1655 | int row) /* Index of the page to be loaded into | |
1656 | * the cache. */ | |
1657 | { | |
1658 | FontFamily *familyPtr; | |
1659 | Tcl_Encoding encoding; | |
1660 | char src[TCL_UTF_MAX], buf[16]; | |
1661 | USHORT *startCount, *endCount; | |
1662 | int i, j, bitOffset, end, segCount; | |
1663 | ||
1664 | subFontPtr->fontMap[row] = (char *) ckalloc(FONTMAP_BITSPERPAGE / 8); | |
1665 | memset(subFontPtr->fontMap[row], 0, FONTMAP_BITSPERPAGE / 8); | |
1666 | ||
1667 | familyPtr = subFontPtr->familyPtr; | |
1668 | encoding = familyPtr->encoding; | |
1669 | ||
1670 | if (familyPtr->encoding == unicodeEncoding) { | |
1671 | /* | |
1672 | * Font is Unicode. Few fonts are going to have all characters, so | |
1673 | * examine the TrueType character existence metrics to determine | |
1674 | * what characters actually exist in this font. | |
1675 | */ | |
1676 | ||
1677 | segCount = familyPtr->segCount; | |
1678 | startCount = familyPtr->startCount; | |
1679 | endCount = familyPtr->endCount; | |
1680 | ||
1681 | j = 0; | |
1682 | end = (row + 1) << FONTMAP_SHIFT; | |
1683 | for (i = row << FONTMAP_SHIFT; i < end; i++) { | |
1684 | for ( ; j < segCount; j++) { | |
1685 | if (endCount[j] >= i) { | |
1686 | if (startCount[j] <= i) { | |
1687 | bitOffset = i & (FONTMAP_BITSPERPAGE - 1); | |
1688 | subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7); | |
1689 | } | |
1690 | break; | |
1691 | } | |
1692 | } | |
1693 | } | |
1694 | } else if (familyPtr->isSymbolFont) { | |
1695 | /* | |
1696 | * Assume that a symbol font with a known encoding has all the | |
1697 | * characters that its encoding claims it supports. | |
1698 | * | |
1699 | * The test for "encoding == unicodeEncoding" | |
1700 | * must occur before this case, to catch all symbol fonts (such | |
1701 | * as {Comic Sans MS} or Wingdings) for which we don't have | |
1702 | * encoding information; those symbol fonts are treated as if | |
1703 | * they were in the Unicode encoding and their symbolic | |
1704 | * character existence metrics are treated as if they were Unicode | |
1705 | * character existence metrics. This way, although we don't know | |
1706 | * the proper Unicode -> symbol font mapping, we can install the | |
1707 | * symbol font as the base font and access its glyphs. | |
1708 | */ | |
1709 | ||
1710 | end = (row + 1) << FONTMAP_SHIFT; | |
1711 | for (i = row << FONTMAP_SHIFT; i < end; i++) { | |
1712 | if (Tcl_UtfToExternal(NULL, encoding, src, | |
1713 | Tcl_UniCharToUtf(i, src), TCL_ENCODING_STOPONERROR, NULL, | |
1714 | buf, sizeof(buf), NULL, NULL, NULL) != TCL_OK) { | |
1715 | continue; | |
1716 | } | |
1717 | bitOffset = i & (FONTMAP_BITSPERPAGE - 1); | |
1718 | subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7); | |
1719 | } | |
1720 | } | |
1721 | } | |
1722 | ||
1723 | /* | |
1724 | *--------------------------------------------------------------------------- | |
1725 | * | |
1726 | * CanUseFallbackWithAliases -- | |
1727 | * | |
1728 | * Helper function for FindSubFontForChar. Determine if the | |
1729 | * specified face name (or an alias of the specified face name) | |
1730 | * can be used to construct a screen font that can display the | |
1731 | * given character. | |
1732 | * | |
1733 | * Results: | |
1734 | * See CanUseFallback(). | |
1735 | * | |
1736 | * Side effects: | |
1737 | * If the name and/or one of its aliases was rejected, the | |
1738 | * rejected string is recorded in nameTriedPtr so that it won't | |
1739 | * be tried again. | |
1740 | * | |
1741 | *--------------------------------------------------------------------------- | |
1742 | */ | |
1743 | ||
1744 | static SubFont * | |
1745 | CanUseFallbackWithAliases( | |
1746 | HDC hdc, /* HDC in which font can be selected. */ | |
1747 | WinFont *fontPtr, /* The font object that will own the new | |
1748 | * screen font. */ | |
1749 | char *faceName, /* Desired face name for new screen font. */ | |
1750 | int ch, /* The Unicode character that the new | |
1751 | * screen font must be able to display. */ | |
1752 | Tcl_DString *nameTriedPtr) /* Records face names that have already | |
1753 | * been tried. It is possible for the same | |
1754 | * face name to be queried multiple times when | |
1755 | * trying to find a suitable screen font. */ | |
1756 | { | |
1757 | int i; | |
1758 | char **aliases; | |
1759 | SubFont *subFontPtr; | |
1760 | ||
1761 | if (SeenName(faceName, nameTriedPtr) == 0) { | |
1762 | subFontPtr = CanUseFallback(hdc, fontPtr, faceName, ch); | |
1763 | if (subFontPtr != NULL) { | |
1764 | return subFontPtr; | |
1765 | } | |
1766 | } | |
1767 | aliases = TkFontGetAliasList(faceName); | |
1768 | if (aliases != NULL) { | |
1769 | for (i = 0; aliases[i] != NULL; i++) { | |
1770 | if (SeenName(aliases[i], nameTriedPtr) == 0) { | |
1771 | subFontPtr = CanUseFallback(hdc, fontPtr, aliases[i], ch); | |
1772 | if (subFontPtr != NULL) { | |
1773 | return subFontPtr; | |
1774 | } | |
1775 | } | |
1776 | } | |
1777 | } | |
1778 | return NULL; | |
1779 | } | |
1780 | ||
1781 | /* | |
1782 | *--------------------------------------------------------------------------- | |
1783 | * | |
1784 | * SeenName -- | |
1785 | * | |
1786 | * Used to determine we have already tried and rejected the given | |
1787 | * face name when looking for a screen font that can support some | |
1788 | * Unicode character. | |
1789 | * | |
1790 | * Results: | |
1791 | * The return value is 0 if this face name has not already been seen, | |
1792 | * non-zero otherwise. | |
1793 | * | |
1794 | * Side effects: | |
1795 | * None. | |
1796 | * | |
1797 | *--------------------------------------------------------------------------- | |
1798 | */ | |
1799 | ||
1800 | static int | |
1801 | SeenName( | |
1802 | CONST char *name, /* The name to check. */ | |
1803 | Tcl_DString *dsPtr) /* Contains names that have already been | |
1804 | * seen. */ | |
1805 | { | |
1806 | CONST char *seen, *end; | |
1807 | ||
1808 | seen = Tcl_DStringValue(dsPtr); | |
1809 | end = seen + Tcl_DStringLength(dsPtr); | |
1810 | while (seen < end) { | |
1811 | if (strcasecmp(seen, name) == 0) { | |
1812 | return 1; | |
1813 | } | |
1814 | seen += strlen(seen) + 1; | |
1815 | } | |
1816 | Tcl_DStringAppend(dsPtr, (char *) name, (int) (strlen(name) + 1)); | |
1817 | return 0; | |
1818 | } | |
1819 | ||
1820 | /* | |
1821 | *------------------------------------------------------------------------- | |
1822 | * | |
1823 | * CanUseFallback -- | |
1824 | * | |
1825 | * If the specified screen font has not already been loaded into | |
1826 | * the font object, determine if it can display the given character. | |
1827 | * | |
1828 | * Results: | |
1829 | * The return value is a pointer to a newly allocated SubFont, owned | |
1830 | * by the font object. This SubFont can be used to display the given | |
1831 | * character. The SubFont represents the screen font with the base set | |
1832 | * of font attributes from the font object, but using the specified | |
1833 | * font name. NULL is returned if the font object already holds | |
1834 | * a reference to the specified physical font or if the specified | |
1835 | * physical font cannot display the given character. | |
1836 | * | |
1837 | * Side effects: | |
1838 | * The font object's subFontArray is updated to contain a reference | |
1839 | * to the newly allocated SubFont. | |
1840 | * | |
1841 | *------------------------------------------------------------------------- | |
1842 | */ | |
1843 | ||
1844 | static SubFont * | |
1845 | CanUseFallback( | |
1846 | HDC hdc, /* HDC in which font can be selected. */ | |
1847 | WinFont *fontPtr, /* The font object that will own the new | |
1848 | * screen font. */ | |
1849 | char *faceName, /* Desired face name for new screen font. */ | |
1850 | int ch) /* The Unicode character that the new | |
1851 | * screen font must be able to display. */ | |
1852 | { | |
1853 | int i; | |
1854 | HFONT hFont; | |
1855 | SubFont subFont; | |
1856 | ||
1857 | if (FamilyExists(hdc, faceName) == 0) { | |
1858 | return NULL; | |
1859 | } | |
1860 | ||
1861 | /* | |
1862 | * Skip all fonts we've already used. | |
1863 | */ | |
1864 | ||
1865 | for (i = 0; i < fontPtr->numSubFonts; i++) { | |
1866 | if (faceName == fontPtr->subFontArray[i].familyPtr->faceName) { | |
1867 | return NULL; | |
1868 | } | |
1869 | } | |
1870 | ||
1871 | /* | |
1872 | * Load this font and see if it has the desired character. | |
1873 | */ | |
1874 | ||
1875 | hFont = GetScreenFont(&fontPtr->font.fa, faceName, fontPtr->pixelSize); | |
1876 | InitSubFont(hdc, hFont, 0, &subFont); | |
1877 | if (((ch < 256) && (subFont.familyPtr->isSymbolFont)) | |
1878 | || (FontMapLookup(&subFont, ch) == 0)) { | |
1879 | /* | |
1880 | * Don't use a symbol font as a fallback font for characters below | |
1881 | * 256. | |
1882 | */ | |
1883 | ||
1884 | ReleaseSubFont(&subFont); | |
1885 | return NULL; | |
1886 | } | |
1887 | ||
1888 | if (fontPtr->numSubFonts >= SUBFONT_SPACE) { | |
1889 | SubFont *newPtr; | |
1890 | ||
1891 | newPtr = (SubFont *) ckalloc(sizeof(SubFont) | |
1892 | * (fontPtr->numSubFonts + 1)); | |
1893 | memcpy((char *) newPtr, fontPtr->subFontArray, | |
1894 | fontPtr->numSubFonts * sizeof(SubFont)); | |
1895 | if (fontPtr->subFontArray != fontPtr->staticSubFonts) { | |
1896 | ckfree((char *) fontPtr->subFontArray); | |
1897 | } | |
1898 | fontPtr->subFontArray = newPtr; | |
1899 | } | |
1900 | fontPtr->subFontArray[fontPtr->numSubFonts] = subFont; | |
1901 | fontPtr->numSubFonts++; | |
1902 | return &fontPtr->subFontArray[fontPtr->numSubFonts - 1]; | |
1903 | } | |
1904 | ||
1905 | /* | |
1906 | *--------------------------------------------------------------------------- | |
1907 | * | |
1908 | * GetScreenFont -- | |
1909 | * | |
1910 | * Given the name and other attributes, construct an HFONT. | |
1911 | * This is where all the alias and fallback substitution bottoms | |
1912 | * out. | |
1913 | * | |
1914 | * Results: | |
1915 | * The screen font that corresponds to the attributes. | |
1916 | * | |
1917 | * Side effects: | |
1918 | * None. | |
1919 | * | |
1920 | *--------------------------------------------------------------------------- | |
1921 | */ | |
1922 | ||
1923 | static HFONT | |
1924 | GetScreenFont( | |
1925 | CONST TkFontAttributes *faPtr, | |
1926 | /* Desired font attributes for new HFONT. */ | |
1927 | CONST char *faceName, /* Overrides font family specified in font | |
1928 | * attributes. */ | |
1929 | int pixelSize) /* Overrides size specified in font | |
1930 | * attributes. */ | |
1931 | { | |
1932 | Tcl_DString ds; | |
1933 | HFONT hFont; | |
1934 | LOGFONTW lf; | |
1935 | ||
1936 | lf.lfHeight = -pixelSize; | |
1937 | lf.lfWidth = 0; | |
1938 | lf.lfEscapement = 0; | |
1939 | lf.lfOrientation = 0; | |
1940 | lf.lfWeight = (faPtr->weight == TK_FW_NORMAL) ? FW_NORMAL : FW_BOLD; | |
1941 | lf.lfItalic = faPtr->slant; | |
1942 | lf.lfUnderline = faPtr->underline; | |
1943 | lf.lfStrikeOut = faPtr->overstrike; | |
1944 | lf.lfCharSet = DEFAULT_CHARSET; | |
1945 | lf.lfOutPrecision = OUT_TT_PRECIS; | |
1946 | lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; | |
1947 | lf.lfQuality = DEFAULT_QUALITY; | |
1948 | lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; | |
1949 | ||
1950 | Tcl_UtfToExternalDString(systemEncoding, faceName, -1, &ds); | |
1951 | ||
1952 | if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { | |
1953 | Tcl_UniChar *src, *dst; | |
1954 | ||
1955 | /* | |
1956 | * We can only store up to LF_FACESIZE wide characters | |
1957 | */ | |
1958 | if (Tcl_DStringLength(&ds) >= (LF_FACESIZE * sizeof(WCHAR))) { | |
1959 | Tcl_DStringSetLength(&ds, LF_FACESIZE); | |
1960 | } | |
1961 | src = (Tcl_UniChar *) Tcl_DStringValue(&ds); | |
1962 | dst = (Tcl_UniChar *) lf.lfFaceName; | |
1963 | while (*src != '\0') { | |
1964 | *dst++ = *src++; | |
1965 | } | |
1966 | *dst = '\0'; | |
1967 | hFont = CreateFontIndirectW(&lf); | |
1968 | } else { | |
1969 | /* | |
1970 | * We can only store up to LF_FACESIZE characters | |
1971 | */ | |
1972 | if (Tcl_DStringLength(&ds) >= LF_FACESIZE) { | |
1973 | Tcl_DStringSetLength(&ds, LF_FACESIZE); | |