1 |
/* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tk_base/tkwinfont.c,v 1.1.1.1 2001/06/13 05:13:30 dtashley Exp $ */
|
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);
|
1974 |
}
|
1975 |
strcpy((char *) lf.lfFaceName, Tcl_DStringValue(&ds));
|
1976 |
hFont = CreateFontIndirectA((LOGFONTA *) &lf);
|
1977 |
}
|
1978 |
Tcl_DStringFree(&ds);
|
1979 |
return hFont;
|
1980 |
}
|
1981 |
|
1982 |
/*
|
1983 |
*-------------------------------------------------------------------------
|
1984 |
*
|
1985 |
* FamilyExists, FamilyOrAliasExists, WinFontExistsProc --
|
1986 |
*
|
1987 |
* Determines if any physical screen font exists on the system with
|
1988 |
* the given family name. If the family exists, then it should be
|
1989 |
* possible to construct some physical screen font with that family
|
1990 |
* name.
|
1991 |
*
|
1992 |
* Results:
|
1993 |
* The return value is 0 if the specified font family does not exist,
|
1994 |
* non-zero otherwise.
|
1995 |
*
|
1996 |
* Side effects:
|
1997 |
* None.
|
1998 |
*
|
1999 |
*-------------------------------------------------------------------------
|
2000 |
*/
|
2001 |
|
2002 |
static int
|
2003 |
FamilyExists(
|
2004 |
HDC hdc, /* HDC in which font family will be used. */
|
2005 |
CONST char *faceName) /* Font family to query. */
|
2006 |
{
|
2007 |
int result;
|
2008 |
Tcl_DString faceString;
|
2009 |
|
2010 |
/*
|
2011 |
* Just immediately rule out the following fonts, because they look so
|
2012 |
* ugly on windows. The caller's fallback mechanism will cause the
|
2013 |
* corresponding appropriate TrueType fonts to be selected.
|
2014 |
*/
|
2015 |
|
2016 |
if (strcasecmp(faceName, "Courier") == 0) {
|
2017 |
return 0;
|
2018 |
}
|
2019 |
if (strcasecmp(faceName, "Times") == 0) {
|
2020 |
return 0;
|
2021 |
}
|
2022 |
if (strcasecmp(faceName, "Helvetica") == 0) {
|
2023 |
return 0;
|
2024 |
}
|
2025 |
|
2026 |
Tcl_UtfToExternalDString(systemEncoding, faceName, -1, &faceString);
|
2027 |
|
2028 |
/*
|
2029 |
* If the family exists, WinFontExistProc() will be called and
|
2030 |
* EnumFontFamilies() will return whatever WinFontExistProc() returns.
|
2031 |
* If the family doesn't exist, EnumFontFamilies() will just return a
|
2032 |
* non-zero value.
|
2033 |
*/
|
2034 |
|
2035 |
if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
|
2036 |
result = EnumFontFamiliesW(hdc, (WCHAR *) Tcl_DStringValue(&faceString),
|
2037 |
(FONTENUMPROCW) WinFontExistProc, 0);
|
2038 |
} else {
|
2039 |
result = EnumFontFamiliesA(hdc, (char *) Tcl_DStringValue(&faceString),
|
2040 |
(FONTENUMPROCA) WinFontExistProc, 0);
|
2041 |
}
|
2042 |
Tcl_DStringFree(&faceString);
|
2043 |
return (result == 0);
|
2044 |
}
|
2045 |
|
2046 |
static char *
|
2047 |
FamilyOrAliasExists(
|
2048 |
HDC hdc,
|
2049 |
CONST char *faceName)
|
2050 |
{
|
2051 |
char **aliases;
|
2052 |
int i;
|
2053 |
|
2054 |
if (FamilyExists(hdc, faceName) != 0) {
|
2055 |
return (char *) faceName;
|
2056 |
}
|
2057 |
aliases = TkFontGetAliasList(faceName);
|
2058 |
if (aliases != NULL) {
|
2059 |
for (i = 0; aliases[i] != NULL; i++) {
|
2060 |
if (FamilyExists(hdc, aliases[i]) != 0) {
|
2061 |
return aliases[i];
|
2062 |
}
|
2063 |
}
|
2064 |
}
|
2065 |
return NULL;
|
2066 |
}
|
2067 |
|
2068 |
static int CALLBACK
|
2069 |
WinFontExistProc(
|
2070 |
ENUMLOGFONT *lfPtr, /* Logical-font data. */
|
2071 |
NEWTEXTMETRIC *tmPtr, /* Physical-font data (not used). */
|
2072 |
int fontType, /* Type of font (not used). */
|
2073 |
LPARAM lParam) /* EnumFontData to hold result. */
|
2074 |
{
|
2075 |
return 0;
|
2076 |
}
|
2077 |
|
2078 |
/*
|
2079 |
* The following data structures are used when querying a TrueType font file
|
2080 |
* to determine which characters the font supports.
|
2081 |
*/
|
2082 |
|
2083 |
#pragma pack(1) /* Structures are byte aligned in file. */
|
2084 |
|
2085 |
#define CMAPHEX 0x636d6170 /* Key for character map resource. */
|
2086 |
|
2087 |
typedef struct CMAPTABLE {
|
2088 |
USHORT version; /* Table version number (0). */
|
2089 |
USHORT numTables; /* Number of encoding tables following. */
|
2090 |
} CMAPTABLE;
|
2091 |
|
2092 |
typedef struct ENCODINGTABLE {
|
2093 |
USHORT platform; /* Platform for which data is targeted.
|
2094 |
* 3 means data is for Windows. */
|
2095 |
USHORT encoding; /* How characters in font are encoded.
|
2096 |
* 1 means that the following subtable is
|
2097 |
* keyed based on Unicode. */
|
2098 |
ULONG offset; /* Byte offset from beginning of CMAPTABLE
|
2099 |
* to the subtable for this encoding. */
|
2100 |
} ENCODINGTABLE;
|
2101 |
|
2102 |
typedef struct ANYTABLE {
|
2103 |
USHORT format; /* Format number. */
|
2104 |
USHORT length; /* The actual length in bytes of this
|
2105 |
* subtable. */
|
2106 |
USHORT version; /* Version number (starts at 0). */
|
2107 |
} ANYTABLE;
|
2108 |
|
2109 |
typedef struct BYTETABLE {
|
2110 |
USHORT format; /* Format number is set to 0. */
|
2111 |
USHORT length; /* The actual length in bytes of this
|
2112 |
* subtable. */
|
2113 |
USHORT version; /* Version number (starts at 0). */
|
2114 |
BYTE glyphIdArray[256]; /* Array that maps up to 256 single-byte char
|
2115 |
* codes to glyph indices. */
|
2116 |
} BYTETABLE;
|
2117 |
|
2118 |
typedef struct SUBHEADER {
|
2119 |
USHORT firstCode; /* First valid low byte for subHeader. */
|
2120 |
USHORT entryCount; /* Number valid low bytes for subHeader. */
|
2121 |
SHORT idDelta; /* Constant adder to get base glyph index. */
|
2122 |
USHORT idRangeOffset; /* Byte offset from here to appropriate
|
2123 |
* glyphIndexArray. */
|
2124 |
} SUBHEADER;
|
2125 |
|
2126 |
typedef struct HIBYTETABLE {
|
2127 |
USHORT format; /* Format number is set to 2. */
|
2128 |
USHORT length; /* The actual length in bytes of this
|
2129 |
* subtable. */
|
2130 |
USHORT version; /* Version number (starts at 0). */
|
2131 |
USHORT subHeaderKeys[256]; /* Maps high bytes to subHeaders: value is
|
2132 |
* subHeader index * 8. */
|
2133 |
#if 0
|
2134 |
SUBHEADER subHeaders[]; /* Variable-length array of SUBHEADERs. */
|
2135 |
USHORT glyphIndexArray[]; /* Variable-length array containing subarrays
|
2136 |
* used for mapping the low byte of 2-byte
|
2137 |
* characters. */
|
2138 |
#endif
|
2139 |
} HIBYTETABLE;
|
2140 |
|
2141 |
typedef struct SEGMENTTABLE {
|
2142 |
USHORT format; /* Format number is set to 4. */
|
2143 |
USHORT length; /* The actual length in bytes of this
|
2144 |
* subtable. */
|
2145 |
USHORT version; /* Version number (starts at 0). */
|
2146 |
USHORT segCountX2; /* 2 x segCount. */
|
2147 |
USHORT searchRange; /* 2 x (2**floor(log2(segCount))). */
|
2148 |
USHORT entrySelector; /* log2(searchRange/2). */
|
2149 |
USHORT rangeShift; /* 2 x segCount - searchRange. */
|
2150 |
#if 0
|
2151 |
USHORT endCount[segCount] /* End characterCode for each segment. */
|
2152 |
USHORT reservedPad; /* Set to 0. */
|
2153 |
USHORT startCount[segCount];/* Start character code for each segment. */
|
2154 |
USHORT idDelta[segCount]; /* Delta for all character in segment. */
|
2155 |
USHORT idRangeOffset[segCount]; /* Offsets into glyphIdArray or 0. */
|
2156 |
USHORT glyphIdArray[] /* Glyph index array. */
|
2157 |
#endif
|
2158 |
} SEGMENTTABLE;
|
2159 |
|
2160 |
typedef struct TRIMMEDTABLE {
|
2161 |
USHORT format; /* Format number is set to 6. */
|
2162 |
USHORT length; /* The actual length in bytes of this
|
2163 |
* subtable. */
|
2164 |
USHORT version; /* Version number (starts at 0). */
|
2165 |
USHORT firstCode; /* First character code of subrange. */
|
2166 |
USHORT entryCount; /* Number of character codes in subrange. */
|
2167 |
#if 0
|
2168 |
USHORT glyphIdArray[]; /* Array of glyph index values for
|
2169 |
character codes in the range. */
|
2170 |
#endif
|
2171 |
} TRIMMEDTABLE;
|
2172 |
|
2173 |
typedef union SUBTABLE {
|
2174 |
ANYTABLE any;
|
2175 |
BYTETABLE byte;
|
2176 |
HIBYTETABLE hiByte;
|
2177 |
SEGMENTTABLE segment;
|
2178 |
TRIMMEDTABLE trimmed;
|
2179 |
} SUBTABLE;
|
2180 |
|
2181 |
#pragma pack()
|
2182 |
|
2183 |
/*
|
2184 |
*-------------------------------------------------------------------------
|
2185 |
*
|
2186 |
* LoadFontRanges --
|
2187 |
*
|
2188 |
* Given an HFONT, get the information about the characters that
|
2189 |
* this font can display.
|
2190 |
*
|
2191 |
* Results:
|
2192 |
* If the font has no Unicode character information, the return value
|
2193 |
* is 0 and *startCountPtr and *endCountPtr are filled with NULL.
|
2194 |
* Otherwise, *startCountPtr and *endCountPtr are set to pointers to
|
2195 |
* arrays of TrueType character existence information and the return
|
2196 |
* value is the length of the arrays (the two arrays are always the
|
2197 |
* same length as each other).
|
2198 |
*
|
2199 |
* Side effects:
|
2200 |
* None.
|
2201 |
*
|
2202 |
*-------------------------------------------------------------------------
|
2203 |
*/
|
2204 |
|
2205 |
static int
|
2206 |
LoadFontRanges(
|
2207 |
HDC hdc, /* HDC into which font can be selected. */
|
2208 |
HFONT hFont, /* HFONT to query. */
|
2209 |
USHORT **startCountPtr, /* Filled with malloced pointer to
|
2210 |
* character range information. */
|
2211 |
USHORT **endCountPtr, /* Filled with malloced pointer to
|
2212 |
* character range information. */
|
2213 |
int *symbolPtr)
|
2214 |
{
|
2215 |
int n, i, swapped, offset, cbData, segCount;
|
2216 |
DWORD cmapKey;
|
2217 |
USHORT *startCount, *endCount;
|
2218 |
CMAPTABLE cmapTable;
|
2219 |
ENCODINGTABLE encTable;
|
2220 |
SUBTABLE subTable;
|
2221 |
char *s;
|
2222 |
|
2223 |
segCount = 0;
|
2224 |
startCount = NULL;
|
2225 |
endCount = NULL;
|
2226 |
*symbolPtr = 0;
|
2227 |
|
2228 |
hFont = SelectObject(hdc, hFont);
|
2229 |
|
2230 |
i = 0;
|
2231 |
s = (char *) &i;
|
2232 |
*s = '\1';
|
2233 |
swapped = 0;
|
2234 |
|
2235 |
if (i == 1) {
|
2236 |
swapped = 1;
|
2237 |
}
|
2238 |
|
2239 |
cmapKey = CMAPHEX;
|
2240 |
if (swapped) {
|
2241 |
SwapLong(&cmapKey);
|
2242 |
}
|
2243 |
|
2244 |
n = GetFontData(hdc, cmapKey, 0, &cmapTable, sizeof(cmapTable));
|
2245 |
if (n != GDI_ERROR) {
|
2246 |
if (swapped) {
|
2247 |
SwapShort(&cmapTable.numTables);
|
2248 |
}
|
2249 |
for (i = 0; i < cmapTable.numTables; i++) {
|
2250 |
offset = sizeof(cmapTable) + i * sizeof(encTable);
|
2251 |
GetFontData(hdc, cmapKey, offset, &encTable, sizeof(encTable));
|
2252 |
if (swapped) {
|
2253 |
SwapShort(&encTable.platform);
|
2254 |
SwapShort(&encTable.encoding);
|
2255 |
SwapLong(&encTable.offset);
|
2256 |
}
|
2257 |
if (encTable.platform != 3) {
|
2258 |
/*
|
2259 |
* Not Microsoft encoding.
|
2260 |
*/
|
2261 |
|
2262 |
continue;
|
2263 |
}
|
2264 |
if (encTable.encoding == 0) {
|
2265 |
*symbolPtr = 1;
|
2266 |
} else if (encTable.encoding != 1) {
|
2267 |
continue;
|
2268 |
}
|
2269 |
|
2270 |
GetFontData(hdc, cmapKey, encTable.offset, &subTable,
|
2271 |
sizeof(subTable));
|
2272 |
if (swapped) {
|
2273 |
SwapShort(&subTable.any.format);
|
2274 |
}
|
2275 |
if (subTable.any.format == 4) {
|
2276 |
if (swapped) {
|
2277 |
SwapShort(&subTable.segment.segCountX2);
|
2278 |
}
|
2279 |
segCount = subTable.segment.segCountX2 / 2;
|
2280 |
cbData = segCount * sizeof(USHORT);
|
2281 |
|
2282 |
startCount = (USHORT *) ckalloc(cbData);
|
2283 |
endCount = (USHORT *) ckalloc(cbData);
|
2284 |
|
2285 |
offset = encTable.offset + sizeof(subTable.segment);
|
2286 |
GetFontData(hdc, cmapKey, offset, endCount, cbData);
|
2287 |
offset += cbData + sizeof(USHORT);
|
2288 |
GetFontData(hdc, cmapKey, offset, startCount, cbData);
|
2289 |
if (swapped) {
|
2290 |
for (i = 0; i < segCount; i++) {
|
2291 |
SwapShort(&endCount[i]);
|
2292 |
SwapShort(&startCount[i]);
|
2293 |
}
|
2294 |
}
|
2295 |
if (*symbolPtr != 0) {
|
2296 |
/*
|
2297 |
* Empirically determined: When a symbol font is
|
2298 |
* loaded, the character existence metrics obtained
|
2299 |
* from the system are mildly wrong. If the real range
|
2300 |
* of the symbol font is from 0020 to 00FE, then the
|
2301 |
* metrics are reported as F020 to F0FE. When we load
|
2302 |
* a symbol font, we must fix the character existence
|
2303 |
* metrics.
|
2304 |
*
|
2305 |
* Symbol fonts should only use the symbol encoding
|
2306 |
* for 8-bit characters [note Bug: 2406]
|
2307 |
*/
|
2308 |
|
2309 |
for (i = 0; i < segCount; i++) {
|
2310 |
if (((startCount[i] & 0xff00) == 0xf000)
|
2311 |
&& ((endCount[i] & 0xff00) == 0xf000)) {
|
2312 |
startCount[i] &= 0xff;
|
2313 |
endCount[i] &= 0xff;
|
2314 |
}
|
2315 |
}
|
2316 |
}
|
2317 |
}
|
2318 |
}
|
2319 |
}
|
2320 |
SelectObject(hdc, hFont);
|
2321 |
|
2322 |
*startCountPtr = startCount;
|
2323 |
*endCountPtr = endCount;
|
2324 |
return segCount;
|
2325 |
}
|
2326 |
|
2327 |
/*
|
2328 |
*-------------------------------------------------------------------------
|
2329 |
*
|
2330 |
* SwapShort, SwapLong --
|
2331 |
*
|
2332 |
* Helper functions to convert the data loaded from TrueType font
|
2333 |
* files to Intel byte ordering.
|
2334 |
*
|
2335 |
* Results:
|
2336 |
* Bytes of input value are swapped and stored back in argument.
|
2337 |
*
|
2338 |
* Side effects:
|
2339 |
* None.
|
2340 |
*
|
2341 |
*-------------------------------------------------------------------------
|
2342 |
*/
|
2343 |
|
2344 |
static void
|
2345 |
SwapShort(PUSHORT p)
|
2346 |
{
|
2347 |
*p = (SHORT)(HIBYTE(*p) + (LOBYTE(*p) << 8));
|
2348 |
}
|
2349 |
|
2350 |
static void
|
2351 |
SwapLong(PULONG p)
|
2352 |
{
|
2353 |
ULONG temp;
|
2354 |
|
2355 |
temp = (LONG) ((BYTE) *p);
|
2356 |
temp <<= 8;
|
2357 |
*p >>=8;
|
2358 |
|
2359 |
temp += (LONG) ((BYTE) *p);
|
2360 |
temp <<= 8;
|
2361 |
*p >>=8;
|
2362 |
|
2363 |
temp += (LONG) ((BYTE) *p);
|
2364 |
temp <<= 8;
|
2365 |
*p >>=8;
|
2366 |
|
2367 |
temp += (LONG) ((BYTE) *p);
|
2368 |
*p = temp;
|
2369 |
}
|
2370 |
|
2371 |
|
2372 |
/* $History: tkWinFont.c $
|
2373 |
*
|
2374 |
* ***************** Version 1 *****************
|
2375 |
* User: Dtashley Date: 1/02/01 Time: 3:15a
|
2376 |
* Created in $/IjuScripter, IjuConsole/Source/Tk Base
|
2377 |
* Initial check-in.
|
2378 |
*/
|
2379 |
|
2380 |
/* End of TKWINFONT.C */ |