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); |
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 |
/* End of tkwinfont.c */ |