Added checking for broken font cache.
[wine.git] / graphics / x11drv / xfont.c
blobce26c4b5d44be526cbdcad7be22af0aba86c6b8d
1 /*
2 * X11 physical font objects
4 * Copyright 1997 Alex Korobka
6 * TODO: Mapping algorithm tweaks, FO_SYNTH_... flags (ExtTextOut() will
7 * have to be changed for that), dynamic font loading (FreeType).
8 */
10 #include "config.h"
12 #include <X11/Xatom.h>
14 #include "ts_xlib.h"
16 #include <ctype.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <math.h>
25 #include <assert.h>
27 #include "windef.h"
28 #include "wingdi.h"
29 #include "winnls.h"
30 #include "heap.h"
31 #include "options.h"
32 #include "font.h"
33 #include "debugtools.h"
34 #include "ldt.h"
35 #include "tweak.h"
36 #include "x11font.h"
37 #include "server.h"
39 DEFAULT_DEBUG_CHANNEL(font);
41 #define X_PFONT_MAGIC (0xFADE0000)
42 #define X_FMC_MAGIC (0x0000CAFE)
44 #define MAX_FONTS 1024*16
45 #define MAX_LFD_LENGTH 256
46 #define TILDE '~'
47 #define HYPHEN '-'
49 #define DEF_POINT_SIZE 8 /* CreateFont(0 .. ) gets this */
50 #define DEF_SCALABLE_HEIGHT 100 /* pixels */
51 #define MIN_FONT_SIZE 2 /* Min size in pixels */
52 #define MAX_FONT_SIZE 1000 /* Max size in pixels */
54 #define REMOVE_SUBSETS 1
55 #define UNMARK_SUBSETS 0
58 #define FF_FAMILY (FF_MODERN | FF_SWISS | FF_ROMAN | FF_DECORATIVE | FF_SCRIPT)
60 typedef struct __fontAlias
62 LPSTR faTypeFace;
63 LPSTR faAlias;
64 struct __fontAlias* next;
65 } fontAlias;
67 static fontAlias *aliasTable = NULL;
69 UINT16 XTextCaps = TC_OP_CHARACTER | TC_OP_STROKE |
70 TC_CP_STROKE | TC_CR_ANY |
71 TC_SA_DOUBLE | TC_SA_INTEGER | TC_SA_CONTIN |
72 TC_UA_ABLE | TC_SO_ABLE | TC_RA_ABLE;
74 /* X11R6 adds TC_SF_X_YINDEP, maybe more... */
76 static const char* INIFontMetrics = "/cachedmetrics.";
77 static const char* INIFontSection = "fonts";
78 static const char* INIAliasSection = "Alias";
79 static const char* INIIgnoreSection = "Ignore";
80 static const char* INIDefault = "Default";
81 static const char* INIDefaultFixed = "DefaultFixed";
82 static const char* INIResolution = "Resolution";
83 static const char* INIGlobalMetrics = "FontMetrics";
84 static const char* INIDefaultSerif = "DefaultSerif";
85 static const char* INIDefaultSansSerif = "DefaultSansSerif";
88 /* FIXME - are there any more Latin charsets ? */
89 #define IS_LATIN_CHARSET(ch) \
90 ((ch)==ANSI_CHARSET ||\
91 (ch)==EE_CHARSET ||\
92 (ch)==ISO3_CHARSET ||\
93 (ch)==ISO4_CHARSET ||\
94 (ch)==RUSSIAN_CHARSET ||\
95 (ch)==ARABIC_CHARSET ||\
96 (ch)==GREEK_CHARSET ||\
97 (ch)==HEBREW_CHARSET ||\
98 (ch)==TURKISH_CHARSET ||\
99 (ch)==BALTIC_CHARSET)
101 /* suffix-charset mapping tables - must be less than 254 entries long */
103 typedef struct __sufch
105 LPSTR psuffix;
106 BYTE charset;
107 UINT16 codepage;
108 } SuffixCharset;
110 static SuffixCharset sufch_ansi[] = {
111 { "0", ANSI_CHARSET, 1252 },
112 { NULL, ANSI_CHARSET, 1252 }};
114 static SuffixCharset sufch_iso646[] = {
115 { "irv", ANSI_CHARSET, 1252 },
116 { NULL, ANSI_CHARSET, 1252 }};
118 static SuffixCharset sufch_iso8859[] = {
119 { "1", ANSI_CHARSET, 28591 },
120 { "2", EE_CHARSET, 28592 },
121 { "3", ISO3_CHARSET, 28593 },
122 { "4", ISO4_CHARSET, 28594 },
123 { "5", RUSSIAN_CHARSET, 28595 },
124 { "6", ARABIC_CHARSET, 28596 },
125 { "7", GREEK_CHARSET, 28597 },
126 { "8", HEBREW_CHARSET, 28598 },
127 { "9", TURKISH_CHARSET, 28599 },
128 { "10", BALTIC_CHARSET, 1257 }, /* FIXME */
129 { "11", THAI_CHARSET, 874 }, /* FIXME */
130 { "12", SYMBOL_CHARSET, CP_SYMBOL },
131 { "13", SYMBOL_CHARSET, CP_SYMBOL },
132 { "14", SYMBOL_CHARSET, CP_SYMBOL },
133 { "15", ANSI_CHARSET, 1252 },
134 { NULL, ANSI_CHARSET, 1252 }};
136 static SuffixCharset sufch_microsoft[] = {
137 { "cp1250", EE_CHARSET, 1250 },
138 { "cp1251", RUSSIAN_CHARSET, 1251 },
139 { "cp1252", ANSI_CHARSET, 1252 },
140 { "cp1253", GREEK_CHARSET, 1253 },
141 { "cp1254", TURKISH_CHARSET, 1254 },
142 { "cp1255", HEBREW_CHARSET, 1255 },
143 { "cp1256", ARABIC_CHARSET, 1256 },
144 { "cp1257", BALTIC_CHARSET, 1257 },
145 { "fontspecific", SYMBOL_CHARSET, CP_SYMBOL },
146 { "symbol", SYMBOL_CHARSET, CP_SYMBOL },
147 { NULL, ANSI_CHARSET, 1252 }};
149 static SuffixCharset sufch_tcvn[] = {
150 { "0", TCVN_CHARSET, 1252 }, /* FIXME */
151 { NULL, TCVN_CHARSET, 1252 }};
153 static SuffixCharset sufch_tis620[] = {
154 { "0", THAI_CHARSET, 874 }, /* FIXME */
155 { NULL, THAI_CHARSET, 874 }};
157 static SuffixCharset sufch_viscii[] = {
158 { "1", VISCII_CHARSET, 1252 }, /* FIXME */
159 { NULL, VISCII_CHARSET, 1252 }};
161 static SuffixCharset sufch_windows[] = {
162 { "1250", EE_CHARSET, 1250 },
163 { "1251", RUSSIAN_CHARSET, 1251 },
164 { "1252", ANSI_CHARSET, 1252 },
165 { "1253", GREEK_CHARSET, 1253 },
166 { "1254", TURKISH_CHARSET, 1254 },
167 { "1255", HEBREW_CHARSET, 1255 },
168 { "1256", ARABIC_CHARSET, 1256 },
169 { "1257", BALTIC_CHARSET, 1257 },
170 { NULL, ANSI_CHARSET, 1252 }};
172 static SuffixCharset sufch_koi8[] = {
173 { "r", RUSSIAN_CHARSET, 20866 },
174 { "u", RUSSIAN_CHARSET, 20866 },
175 { NULL, RUSSIAN_CHARSET, 20866 }};
177 /* FIXME: DBCS charsets need 2 or more fonts */
178 static SuffixCharset sufch_jisx0201[] = {
179 { "0", ANSI_CHARSET, 932 },
180 { NULL, ANSI_CHARSET, 932 }};
182 static SuffixCharset sufch_jisx0208[] = {
183 { "0", SHIFTJIS_CHARSET, 932 },
184 { NULL, SHIFTJIS_CHARSET, 932 }};
186 static SuffixCharset sufch_ksc5601[] = {
187 { "0", HANGEUL_CHARSET, 949 },
188 { NULL, HANGEUL_CHARSET, 949 }};
190 static SuffixCharset sufch_gb2312[] = {
191 { "0", GB2312_CHARSET, 936 },
192 { NULL, GB2312_CHARSET, 936 }};
194 static SuffixCharset sufch_big5[] = {
195 { "0", CHINESEBIG5_CHARSET, 950 },
196 { NULL, CHINESEBIG5_CHARSET, 950 }};
198 static SuffixCharset sufch_unicode[] = {
199 { "0", DEFAULT_CHARSET, 0 },
200 { NULL, DEFAULT_CHARSET, 0 }};
202 static SuffixCharset sufch_iso10646[] = {
203 { "1", DEFAULT_CHARSET, 0 },
204 { NULL, DEFAULT_CHARSET, 0 }};
206 /* Each of these must be matched explicitly */
207 static SuffixCharset sufch_any[] = {
208 { "fontspecific", SYMBOL_CHARSET, CP_SYMBOL },
209 { NULL, 0, 0 }};
212 typedef struct __fet
214 LPSTR prefix;
215 SuffixCharset* sufch;
216 struct __fet* next;
217 } fontEncodingTemplate;
219 /* Note: we can attach additional encoding mappings to the end
220 * of this table at runtime.
222 static fontEncodingTemplate __fETTable[] = {
223 { "ansi", sufch_ansi, &__fETTable[1] },
224 { "ascii", sufch_ansi, &__fETTable[2] },
225 { "iso646.1991", sufch_iso646, &__fETTable[3] },
226 { "iso8859", sufch_iso8859, &__fETTable[4] },
227 { "microsoft", sufch_microsoft, &__fETTable[5] },
228 { "tcvn", sufch_tcvn, &__fETTable[6] },
229 { "tis620.2533", sufch_tis620, &__fETTable[7] },
230 { "viscii1.1", sufch_viscii, &__fETTable[8] },
231 { "windows", sufch_windows, &__fETTable[9] },
232 { "koi8", sufch_koi8, &__fETTable[10]},
233 { "jisx0201.1976",sufch_jisx0201, &__fETTable[11]},
234 { "jisc6226.1978",sufch_jisx0208, &__fETTable[12]},
235 { "jisx0208.1983",sufch_jisx0208, &__fETTable[13]},
236 { "jisx0208.1990",sufch_jisx0208, &__fETTable[14]},
237 { "ksc5601.1987", sufch_ksc5601, &__fETTable[15]},
238 { "gb2312.1980", sufch_gb2312, &__fETTable[16]},
239 { "big5.et", sufch_big5, &__fETTable[17]},
240 { "unicode", sufch_unicode, &__fETTable[18]},
241 { "iso10646", sufch_iso10646, &__fETTable[19]},
242 /* NULL prefix matches anything so put it last */
243 { NULL, sufch_any, NULL },
245 static fontEncodingTemplate* fETTable = __fETTable;
247 static int DefResolution = 0;
249 static CRITICAL_SECTION crtsc_fonts_X11 = CRITICAL_SECTION_INIT;
251 static fontResource* fontList = NULL;
252 static fontObject* fontCache = NULL; /* array */
253 static int fontCacheSize = FONTCACHE;
254 static int fontLF = -1, fontMRU = -1; /* last free, most recently used */
256 #define __PFONT(pFont) ( fontCache + ((UINT)(pFont) & 0x0000FFFF) )
257 #define CHECK_PFONT(pFont) ( (((UINT)(pFont) & 0xFFFF0000) == X_PFONT_MAGIC) &&\
258 (((UINT)(pFont) & 0x0000FFFF) < fontCacheSize) )
260 static Atom RAW_ASCENT;
261 static Atom RAW_DESCENT;
263 /***********************************************************************
264 * Helper macros from X distribution
267 #define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
268 (((cs)->rbearing|(cs)->lbearing| \
269 (cs)->ascent|(cs)->descent) == 0))
271 #define CI_GET_CHAR_INFO(fs,col,def,cs) \
273 cs = def; \
274 if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
275 if (fs->per_char == NULL) { \
276 cs = &fs->min_bounds; \
277 } else { \
278 cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
279 if (CI_NONEXISTCHAR(cs)) cs = def; \
284 #define CI_GET_DEFAULT_INFO(fs,cs) \
285 CI_GET_CHAR_INFO(fs, fs->default_char, NULL, cs)
287 /***********************************************************************
288 * Checksums
290 static UINT16 __lfCheckSum( LPLOGFONT16 plf )
292 CHAR font[LF_FACESIZE];
293 UINT16 checksum = 0;
294 UINT16 i;
296 #define ptr ((UINT16*)plf)
297 for( i = 0; i < 9; i++ ) checksum ^= *ptr++;
298 #undef ptr
299 i = 0;
300 #define ptr ((CHAR*)plf)
301 do { font[i++] = tolower(*ptr++); } while (( i < LF_FACESIZE) && (*ptr) && (*ptr!=' '));
302 for( ptr = font, i >>= 1; i > 0; i-- )
303 #undef ptr
304 #define ptr ((UINT16*)plf)
305 checksum ^= *ptr++;
306 #undef ptr
307 return checksum;
310 static UINT16 __genericCheckSum( const void *ptr, int size )
312 unsigned int checksum = 0;
313 const char *p = (const char *)ptr;
314 while (size-- > 0)
315 checksum ^= (checksum << 3) + (checksum >> 29) + *p++;
317 return checksum & 0xffff;
320 /*************************************************************************
321 * LFD parse/compose routines
323 * NB. LFD_Parse will use lpFont for its own ends, so if you want to keep it
324 * make a copy first
326 * These functions also do TILDE to HYPHEN conversion
328 static LFD* LFD_Parse(LPSTR lpFont)
330 LFD* lfd;
331 char *lpch = lpFont, *lfd_fld[LFD_FIELDS], *field_start;
332 int i;
333 if (*lpch != HYPHEN)
335 WARN("font '%s' doesn't begin with '%c'\n", lpFont, HYPHEN);
336 return NULL;
339 field_start = ++lpch;
340 for( i = 0; i < LFD_FIELDS; )
342 if (*lpch == HYPHEN)
344 *lpch = '\0';
345 lfd_fld[i] = field_start;
346 i++;
347 field_start = ++lpch;
349 else if (!*lpch)
351 lfd_fld[i] = field_start;
352 i++;
353 break;
355 else if (*lpch == TILDE)
357 *lpch = HYPHEN;
358 ++lpch;
360 else
361 ++lpch;
363 /* Fill in the empty fields with NULLS */
364 for (; i< LFD_FIELDS; i++)
365 lfd_fld[i] = NULL;
366 if (*lpch)
367 WARN("Extra ignored in font '%s'\n", lpFont);
369 lfd = HeapAlloc( GetProcessHeap(), 0, sizeof(LFD) );
370 if (lfd)
372 lfd->foundry = lfd_fld[0];
373 lfd->family = lfd_fld[1];
374 lfd->weight = lfd_fld[2];
375 lfd->slant = lfd_fld[3];
376 lfd->set_width = lfd_fld[4];
377 lfd->add_style = lfd_fld[5];
378 lfd->pixel_size = lfd_fld[6];
379 lfd->point_size = lfd_fld[7];
380 lfd->resolution_x = lfd_fld[8];
381 lfd->resolution_y = lfd_fld[9];
382 lfd->spacing = lfd_fld[10];
383 lfd->average_width = lfd_fld[11];
384 lfd->charset_registry = lfd_fld[12];
385 lfd->charset_encoding = lfd_fld[13];
387 return lfd;
391 static void LFD_UnParse(LPSTR dp, UINT buf_size, LFD* lfd)
393 char* lfd_fld[LFD_FIELDS];
394 int i;
396 if (!buf_size)
397 return; /* Dont be silly */
399 lfd_fld[0] = lfd->foundry;
400 lfd_fld[1] = lfd->family;
401 lfd_fld[2] = lfd->weight ;
402 lfd_fld[3] = lfd->slant ;
403 lfd_fld[4] = lfd->set_width ;
404 lfd_fld[5] = lfd->add_style;
405 lfd_fld[6] = lfd->pixel_size;
406 lfd_fld[7] = lfd->point_size;
407 lfd_fld[8] = lfd->resolution_x;
408 lfd_fld[9] = lfd->resolution_y ;
409 lfd_fld[10] = lfd->spacing ;
410 lfd_fld[11] = lfd->average_width ;
411 lfd_fld[12] = lfd->charset_registry ;
412 lfd_fld[13] = lfd->charset_encoding ;
414 buf_size--; /* Room for the terminator */
416 for (i = 0; i < LFD_FIELDS; i++)
418 char* sp = lfd_fld[i];
419 if (!sp || !buf_size)
420 break;
422 *dp++ = HYPHEN;
423 buf_size--;
424 while (buf_size > 0 && *sp)
426 *dp = (*sp == HYPHEN) ? TILDE : *sp;
427 buf_size--;
428 dp++; sp++;
431 *dp = '\0';
435 static void LFD_GetWeight( fontInfo* fi, LPCSTR lpStr)
437 int j = strlen(lpStr);
438 if( j == 1 && *lpStr == '0')
439 fi->fi_flags |= FI_POLYWEIGHT;
440 else if( j == 4 )
442 if( !strcasecmp( "bold", lpStr) )
443 fi->df.dfWeight = FW_BOLD;
444 else if( !strcasecmp( "demi", lpStr) )
446 fi->fi_flags |= FI_FW_DEMI;
447 fi->df.dfWeight = FW_DEMIBOLD;
449 else if( !strcasecmp( "book", lpStr) )
451 fi->fi_flags |= FI_FW_BOOK;
452 fi->df.dfWeight = FW_REGULAR;
455 else if( j == 5 )
457 if( !strcasecmp( "light", lpStr) )
458 fi->df.dfWeight = FW_LIGHT;
459 else if( !strcasecmp( "black", lpStr) )
460 fi->df.dfWeight = FW_BLACK;
462 else if( j == 6 && !strcasecmp( "medium", lpStr) )
463 fi->df.dfWeight = FW_REGULAR;
464 else if( j == 8 && !strcasecmp( "demibold", lpStr) )
465 fi->df.dfWeight = FW_DEMIBOLD;
466 else
467 fi->df.dfWeight = FW_DONTCARE; /* FIXME: try to get something
468 * from the weight property */
471 static BOOL LFD_GetSlant( fontInfo* fi, LPCSTR lpStr)
473 int l = strlen(lpStr);
474 if( l == 1 )
476 switch( tolower( *lpStr ) )
478 case '0': fi->fi_flags |= FI_POLYSLANT; /* haven't seen this one yet */
479 default:
480 case 'r': fi->df.dfItalic = 0;
481 break;
482 case 'o':
483 fi->fi_flags |= FI_OBLIQUE;
484 case 'i': fi->df.dfItalic = 1;
485 break;
487 return FALSE;
489 return TRUE;
492 static void LFD_GetStyle( fontInfo* fi, LPCSTR lpstr, int dec_style_check)
494 int j = strlen(lpstr);
495 if( j > 3 ) /* find out is there "sans" or "script" */
497 j = 0;
499 if( strstr(lpstr, "sans") )
501 fi->df.dfPitchAndFamily |= FF_SWISS;
502 j = 1;
504 if( strstr(lpstr, "script") )
506 fi->df.dfPitchAndFamily |= FF_SCRIPT;
507 j = 1;
509 if( !j && dec_style_check )
510 fi->df.dfPitchAndFamily |= FF_DECORATIVE;
514 /*************************************************************************
515 * LFD_InitFontInfo
517 * INIT ONLY
519 * Fill in some fields in the fontInfo struct.
521 static int LFD_InitFontInfo( fontInfo* fi, const LFD* lfd, LPCSTR fullname )
523 int i, j, dec_style_check, scalability;
524 fontEncodingTemplate* boba;
525 const char* ridiculous = "font '%s' has ridiculous %s\n";
526 char* lpstr;
528 if (!lfd->charset_registry)
530 WARN("font '%s' does not have enough fields\n", fullname);
531 return FALSE;
534 memset(fi, 0, sizeof(fontInfo) );
536 /* weight name - */
537 LFD_GetWeight( fi, lfd->weight);
539 /* slant - */
540 dec_style_check = LFD_GetSlant( fi, lfd->slant);
542 /* width name - */
543 lpstr = lfd->set_width;
544 if( strcasecmp( "normal", lpstr) ) /* XXX 'narrow', 'condensed', etc... */
545 dec_style_check = TRUE;
546 else
547 fi->fi_flags |= FI_NORMAL;
549 /* style - */
550 LFD_GetStyle(fi, lfd->add_style, dec_style_check);
552 /* pixel & decipoint height, and res_x & y */
554 scalability = 0;
556 j = strlen(lfd->pixel_size);
557 if( j == 0 || j > 3 )
559 WARN(ridiculous, fullname, "pixel_size");
560 return FALSE;
562 if( !(fi->lfd_height = atoi(lfd->pixel_size)) )
563 scalability++;
565 j = strlen(lfd->point_size);
566 if( j == 0 || j > 3 )
568 WARN(ridiculous, fullname, "point_size");
569 return FALSE;
571 if( !(atoi(lfd->point_size)) )
572 scalability++;
574 j = strlen(lfd->resolution_x);
575 if( j == 0 || j > 3 )
577 WARN(ridiculous, fullname, "resolution_x");
578 return FALSE;
580 if( !(fi->lfd_resolution = atoi(lfd->resolution_x)) )
581 scalability++;
583 j = strlen(lfd->resolution_y);
584 if( j == 0 || j > 3 )
586 WARN(ridiculous, fullname, "resolution_y");
587 return FALSE;
589 if( !(atoi(lfd->resolution_y)) )
590 scalability++;
592 /* Check scalability */
593 switch (scalability)
595 case 0: /* Bitmap */
596 break;
597 case 4: /* Scalable */
598 fi->fi_flags |= FI_SCALABLE;
599 break;
600 case 2:
601 /* #$%^!!! X11R6 mutant garbage (scalable bitmap) */
602 TRACE("Skipping scalable bitmap '%s'\n", fullname);
603 return FALSE;
604 default:
605 WARN("Font '%s' has weird scalability\n", fullname);
606 return FALSE;
609 /* spacing - */
610 lpstr = lfd->spacing;
611 switch( *lpstr )
613 case '\0':
614 WARN("font '%s' has no spacing\n", fullname);
615 return FALSE;
617 case 'p': fi->fi_flags |= FI_VARIABLEPITCH;
618 break;
619 case 'c': fi->df.dfPitchAndFamily |= FF_MODERN;
620 fi->fi_flags |= FI_FIXEDEX;
621 /* fall through */
622 case 'm': fi->fi_flags |= FI_FIXEDPITCH;
623 break;
624 default:
625 /* Of course this line does nothing */
626 fi->df.dfPitchAndFamily |= DEFAULT_PITCH | FF_DONTCARE;
629 /* average width - */
630 lpstr = lfd->average_width;
631 j = strlen(lpstr);
632 if( j == 0 || j > 3 )
634 WARN(ridiculous, fullname, "average_width");
635 return FALSE;
638 if( !(atoi(lpstr)) && !scalability )
640 WARN("font '%s' has average_width 0 but is not scalable!!\n", fullname);
641 return FALSE;
644 /* charset registry, charset encoding - */
645 lpstr = lfd->charset_registry;
646 if( strstr(lpstr, "jisx") ||
647 strstr(lpstr, "jisc") ||
648 strstr(lpstr, "ksc") ||
649 strstr(lpstr, "gb2312") ||
650 strstr(lpstr, "big5") )
652 FIXME("DBCS fonts like '%s' are not worked correctly now.\n", fullname);
655 fi->df.dfCharSet = ANSI_CHARSET;
657 for( i = 0, boba = fETTable; boba; boba = boba->next, i++ )
659 if (!boba->prefix || !strcasecmp(lpstr, boba->prefix))
661 if (lfd->charset_encoding)
663 for( j = 0; boba->sufch[j].psuffix; j++ )
665 if( !strcasecmp(lfd->charset_encoding, boba->sufch[j].psuffix ))
667 fi->df.dfCharSet = boba->sufch[j].charset;
668 fi->codepage = boba->sufch[j].codepage;
669 goto done;
672 if (boba->prefix)
674 WARN("font '%s' has unknown character encoding '%s'\n",
675 fullname, lfd->charset_encoding);
676 fi->df.dfCharSet = boba->sufch[j].charset;
677 fi->codepage = boba->sufch[j].codepage;
678 j = 254;
679 goto done;
682 else if (boba->prefix)
684 for( j = 0; boba->sufch[j].psuffix; j++ )
686 fi->df.dfCharSet = boba->sufch[j].charset;
687 fi->codepage = boba->sufch[j].codepage;
688 j = 255;
689 goto done;
693 WARN("font '%s' has unknown character set '%s'\n", fullname, lpstr);
694 return FALSE;
696 done:
697 /* i - index into fETTable
698 * j - index into suffix array for fETTable[i]
699 * except:
700 * 254 - unknown suffix
701 * 255 - no suffix at all.
703 fi->fi_encoding = 256 * (UINT16)i + (UINT16)j;
705 return TRUE;
709 /*************************************************************************
710 * LFD_AngleMatrix
712 * make a matrix suitable for LFD based on theta radians
714 static void LFD_AngleMatrix( char* buffer, int h, double theta)
716 double matrix[4];
717 matrix[0] = h*cos(theta);
718 matrix[1] = h*sin(theta);
719 matrix[2] = -h*sin(theta);
720 matrix[3] = h*cos(theta);
721 sprintf(buffer, "[%+f%+f%+f%+f]", matrix[0], matrix[1], matrix[2], matrix[3]);
724 /*************************************************************************
725 * LFD_ComposeLFD
727 * Note: uRelax is a treatment not a cure. Font mapping algorithm
728 * should be bulletproof enough to allow us to avoid hacks like
729 * this despite LFD being so braindead.
731 static BOOL LFD_ComposeLFD( const fontObject* fo,
732 INT height, LPSTR lpLFD, UINT uRelax )
734 int i, h;
735 char *any = "*";
736 char h_string[64], resx_string[64], resy_string[64];
737 LFD aLFD;
739 /* Get the worst case over with first */
741 /* RealizeFont() will call us repeatedly with increasing uRelax
742 * until XLoadFont() succeeds.
743 * to avoid an infinite loop; these will always match
745 if (uRelax >= 5)
747 if (uRelax == 5)
748 sprintf( lpLFD, "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-1" );
749 else
750 sprintf( lpLFD, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" );
751 return TRUE;
754 /* read foundry + family from fo */
755 aLFD.foundry = fo->fr->resource->foundry;
756 aLFD.family = fo->fr->resource->family;
758 /* add weight */
759 switch( fo->fi->df.dfWeight )
761 case FW_BOLD:
762 aLFD.weight = "bold"; break;
763 case FW_REGULAR:
764 if( fo->fi->fi_flags & FI_FW_BOOK )
765 aLFD.weight = "book";
766 else
767 aLFD.weight = "medium";
768 break;
769 case FW_DEMIBOLD:
770 aLFD.weight = "demi";
771 if( !( fo->fi->fi_flags & FI_FW_DEMI) )
772 aLFD.weight = "bold";
773 break;
774 case FW_BLACK:
775 aLFD.weight = "black"; break;
776 case FW_LIGHT:
777 aLFD.weight = "light"; break;
778 default:
779 aLFD.weight = any;
782 /* add slant */
783 if( fo->fi->df.dfItalic )
784 if( fo->fi->fi_flags & FI_OBLIQUE )
785 aLFD.slant = "o";
786 else
787 aLFD.slant = "i";
788 else
789 aLFD.slant = (uRelax < 1) ? "r" : any;
791 /* add width */
792 if( fo->fi->fi_flags & FI_NORMAL )
793 aLFD.set_width = "normal";
794 else
795 aLFD.set_width = any;
797 /* ignore style */
798 aLFD.add_style = any;
800 /* add pixelheight
802 * FIXME: fill in lpXForm and lpPixmap for rotated fonts
804 if( fo->fo_flags & FO_SYNTH_HEIGHT )
805 h = fo->fi->lfd_height;
806 else
808 h = (fo->fi->lfd_height * height + (fo->fi->df.dfPixHeight>>1));
809 h /= fo->fi->df.dfPixHeight;
811 if (h < MIN_FONT_SIZE) /* Resist rounding down to 0 */
812 h = MIN_FONT_SIZE;
813 else if (h > MAX_FONT_SIZE) /* Sanity check as huge fonts can lock up the font server */
815 WARN("Huge font size %d pixels has been reduced to %d\n", h, MAX_FONT_SIZE);
816 h = MAX_FONT_SIZE;
819 if (uRelax <= 2)
820 /* handle rotated fonts */
821 if (fo->lf.lfEscapement) {
822 /* escapement is in tenths of degrees, theta is in radians */
823 double theta = M_PI*fo->lf.lfEscapement/1800.;
824 LFD_AngleMatrix(h_string, h, theta);
826 else
828 sprintf(h_string, "%d", h);
830 else
831 sprintf(h_string, "%d", fo->fi->lfd_height);
833 aLFD.pixel_size = h_string;
834 aLFD.point_size = any;
836 /* resolution_x,y, average width */
837 /* FOX ME - Why do some font servers ignore average width ?
838 * so that you have to mess around with res_y
840 aLFD.average_width = any;
841 if (uRelax <= 3)
843 sprintf(resx_string, "%d", fo->fi->lfd_resolution);
844 aLFD.resolution_x = resx_string;
846 strcpy(resy_string, resx_string);
847 if( uRelax == 0 && XTextCaps & TC_SF_X_YINDEP )
849 if( fo->lf.lfWidth && !(fo->fo_flags & FO_SYNTH_WIDTH))
851 int resy = 0.5 + fo->fi->lfd_resolution *
852 (fo->fi->df.dfAvgWidth * height) /
853 (fo->lf.lfWidth * fo->fi->df.dfPixHeight) ;
854 sprintf(resy_string, "%d", resy);
856 else
857 ; /* FIXME - synth width */
859 aLFD.resolution_y = resy_string;
861 else
863 aLFD.resolution_x = aLFD.resolution_y = any;
866 /* spacing */
868 char* w;
870 if( fo->fi->fi_flags & FI_FIXEDPITCH )
871 w = ( fo->fi->fi_flags & FI_FIXEDEX ) ? "c" : "m";
872 else
873 w = ( fo->fi->fi_flags & FI_VARIABLEPITCH ) ? "p" : any;
875 aLFD.spacing = (uRelax <= 1) ? w : any;
878 /* encoding */
880 if (uRelax <= 4)
882 fontEncodingTemplate* boba;
884 i = fo->fi->fi_encoding >> 8;
885 for( boba = fETTable; i; i--, boba = boba->next );
887 aLFD.charset_registry = boba->prefix ? boba->prefix : any;
889 i = fo->fi->fi_encoding & 255;
890 switch( i )
892 default:
893 aLFD.charset_encoding = boba->sufch[i].psuffix;
894 break;
896 case 254:
897 aLFD.charset_encoding = any;
898 break;
900 case 255: /* no suffix - it ends eg "-ascii" */
901 aLFD.charset_encoding = NULL;
902 break;
905 else
907 aLFD.charset_registry = any;
908 aLFD.charset_encoding = any;
911 LFD_UnParse(lpLFD, MAX_LFD_LENGTH, &aLFD);
913 TRACE("\tLFD(uRelax=%d): %s\n", uRelax, lpLFD );
914 return TRUE;
918 /***********************************************************************
919 * X Font Resources
921 * font info - http://www.microsoft.com/kb/articles/q65/1/23.htm
922 * Windows font metrics - http://www.microsoft.com/kb/articles/q32/6/67.htm
924 static void XFONT_GetLeading( const LPIFONTINFO16 pFI, const XFontStruct* x_fs,
925 INT16* pIL, INT16* pEL, const XFONTTRANS *XFT )
927 unsigned long height;
928 unsigned min = (unsigned char)pFI->dfFirstChar;
929 BOOL bIsLatin = IS_LATIN_CHARSET(pFI->dfCharSet);
931 if( pEL ) *pEL = 0;
933 if(XFT) {
934 Atom RAW_CAP_HEIGHT = TSXInternAtom(display, "RAW_CAP_HEIGHT", TRUE);
935 if(TSXGetFontProperty((XFontStruct*)x_fs, RAW_CAP_HEIGHT, &height))
936 *pIL = XFT->ascent -
937 (INT)(XFT->pixelsize / 1000.0 * height);
938 else
939 *pIL = 0;
940 return;
943 if( TSXGetFontProperty((XFontStruct*)x_fs, XA_CAP_HEIGHT, &height) == FALSE )
945 if( x_fs->per_char )
946 if( bIsLatin )
947 height = x_fs->per_char['X' - min].ascent;
948 else
949 if (x_fs->ascent >= x_fs->max_bounds.ascent)
950 height = x_fs->max_bounds.ascent;
951 else
953 height = x_fs->ascent;
954 if( pEL )
955 *pEL = x_fs->max_bounds.ascent - height;
957 else
958 height = x_fs->min_bounds.ascent;
961 *pIL = x_fs->ascent - height;
964 /***********************************************************************
965 * XFONT_CharWidth
967 static int XFONT_CharWidth(const XFontStruct* x_fs,
968 const XFONTTRANS *XFT, int ch)
970 if(!XFT)
971 return x_fs->per_char[ch].width;
972 else
973 return x_fs->per_char[ch].attributes * XFT->pixelsize / 1000.0;
976 /***********************************************************************
977 * XFONT_GetAvgCharWidth
979 static INT XFONT_GetAvgCharWidth( LPIFONTINFO16 pFI, const XFontStruct* x_fs,
980 const XFONTTRANS *XFT)
982 unsigned min = (unsigned char)pFI->dfFirstChar;
983 unsigned max = (unsigned char)pFI->dfLastChar;
985 INT avg;
987 if( x_fs->per_char )
989 int width = 0, chars = 0, j;
990 if( IS_LATIN_CHARSET(pFI->dfCharSet))
992 /* FIXME - should use a weighted average */
993 for( j = 0; j < 26; j++ )
994 width += XFONT_CharWidth(x_fs, XFT, 'a' + j - min) +
995 XFONT_CharWidth(x_fs, XFT, 'A' + j - min);
996 chars = 52;
998 else /* unweighted average of everything */
1000 for( j = 0, max -= min; j <= max; j++ )
1001 if( !CI_NONEXISTCHAR(x_fs->per_char + j) )
1003 width += XFONT_CharWidth(x_fs, XFT, j);
1004 chars++;
1007 if (chars) avg = (width + (chars>>1))/ chars;
1008 else avg = 0; /* No characters exist at all */
1010 else /* uniform width */
1011 avg = x_fs->min_bounds.width;
1013 return avg;
1016 /***********************************************************************
1017 * XFONT_GetMaxCharWidth
1019 static INT XFONT_GetMaxCharWidth(const XFontStruct* xfs, const XFONTTRANS *XFT)
1021 unsigned min = (unsigned char)xfs->min_char_or_byte2;
1022 unsigned max = (unsigned char)xfs->max_char_or_byte2;
1023 int maxwidth, j;
1025 if(!XFT || !xfs->per_char)
1026 return abs(xfs->max_bounds.width);
1028 for( j = 0, maxwidth = 0, max -= min; j <= max; j++ )
1029 if( !CI_NONEXISTCHAR(xfs->per_char + j) )
1030 if(maxwidth < xfs->per_char[j].attributes)
1031 maxwidth = xfs->per_char[j].attributes;
1033 maxwidth *= XFT->pixelsize / 1000.0;
1034 return maxwidth;
1037 /***********************************************************************
1038 * XFONT_SetFontMetric
1040 * INIT ONLY
1042 * Initializes IFONTINFO16.
1044 static void XFONT_SetFontMetric(fontInfo* fi, const fontResource* fr, XFontStruct* xfs)
1046 unsigned min, max;
1047 fi->df.dfFirstChar = (BYTE)(min = xfs->min_char_or_byte2);
1048 fi->df.dfLastChar = (BYTE)(max = xfs->max_char_or_byte2);
1050 fi->df.dfDefaultChar = (BYTE)xfs->default_char;
1051 fi->df.dfBreakChar = (BYTE)(( ' ' < min || ' ' > max) ? xfs->default_char: ' ');
1053 fi->df.dfPixHeight = (INT16)((fi->df.dfAscent = (INT16)xfs->ascent) + xfs->descent);
1054 fi->df.dfPixWidth = (xfs->per_char) ? 0 : xfs->min_bounds.width;
1056 XFONT_GetLeading( &fi->df, xfs, &fi->df.dfInternalLeading, &fi->df.dfExternalLeading, NULL );
1057 fi->df.dfAvgWidth = (INT16)XFONT_GetAvgCharWidth(&fi->df, xfs, NULL );
1058 fi->df.dfMaxWidth = (INT16)XFONT_GetMaxCharWidth(xfs, NULL);
1060 if( xfs->min_bounds.width != xfs->max_bounds.width )
1061 fi->df.dfPitchAndFamily |= TMPF_FIXED_PITCH; /* au contraire! */
1062 if( fi->fi_flags & FI_SCALABLE )
1064 fi->df.dfType = DEVICE_FONTTYPE;
1065 fi->df.dfPitchAndFamily |= TMPF_DEVICE;
1067 else if( fi->fi_flags & FI_TRUETYPE )
1068 fi->df.dfType = TRUETYPE_FONTTYPE;
1069 else
1070 fi->df.dfType = RASTER_FONTTYPE;
1072 fi->df.dfFace = fr->lfFaceName;
1075 /***********************************************************************
1076 * XFONT_GetTextMetrics
1078 * GetTextMetrics() back end.
1080 static void XFONT_GetTextMetrics( const fontObject* pfo, const LPTEXTMETRICA pTM )
1082 LPIFONTINFO16 pdf = &pfo->fi->df;
1084 if( ! pfo->lpX11Trans ) {
1085 pTM->tmAscent = pfo->fs->ascent;
1086 pTM->tmDescent = pfo->fs->descent;
1087 } else {
1088 pTM->tmAscent = pfo->lpX11Trans->ascent;
1089 pTM->tmDescent = pfo->lpX11Trans->descent;
1092 pTM->tmAscent *= pfo->rescale;
1093 pTM->tmDescent *= pfo->rescale;
1095 pTM->tmHeight = pTM->tmAscent + pTM->tmDescent;
1097 pTM->tmAveCharWidth = pfo->foAvgCharWidth * pfo->rescale;
1098 pTM->tmMaxCharWidth = pfo->foMaxCharWidth * pfo->rescale;
1100 pTM->tmInternalLeading = pfo->foInternalLeading * pfo->rescale;
1101 pTM->tmExternalLeading = pdf->dfExternalLeading * pfo->rescale;
1103 pTM->tmStruckOut = (pfo->fo_flags & FO_SYNTH_STRIKEOUT )
1104 ? 1 : pdf->dfStrikeOut;
1105 pTM->tmUnderlined = (pfo->fo_flags & FO_SYNTH_UNDERLINE )
1106 ? 1 : pdf->dfUnderline;
1108 pTM->tmOverhang = 0;
1109 if( pfo->fo_flags & FO_SYNTH_ITALIC )
1111 pTM->tmOverhang += pTM->tmHeight/3;
1112 pTM->tmItalic = 1;
1113 } else
1114 pTM->tmItalic = pdf->dfItalic;
1116 pTM->tmWeight = pdf->dfWeight;
1117 if( pfo->fo_flags & FO_SYNTH_BOLD )
1119 pTM->tmOverhang++;
1120 pTM->tmWeight += 100;
1123 pTM->tmFirstChar = pdf->dfFirstChar;
1124 pTM->tmLastChar = pdf->dfLastChar;
1125 pTM->tmDefaultChar = pdf->dfDefaultChar;
1126 pTM->tmBreakChar = pdf->dfBreakChar;
1128 pTM->tmCharSet = pdf->dfCharSet;
1129 pTM->tmPitchAndFamily = pdf->dfPitchAndFamily;
1131 pTM->tmDigitizedAspectX = pdf->dfHorizRes;
1132 pTM->tmDigitizedAspectY = pdf->dfVertRes;
1135 /***********************************************************************
1136 * XFONT_GetFontMetric
1138 * Retrieve font metric info (enumeration).
1140 static UINT XFONT_GetFontMetric( const fontInfo* pfi, const LPENUMLOGFONTEX16 pLF,
1141 const LPNEWTEXTMETRIC16 pTM )
1143 memset( pLF, 0, sizeof(*pLF) );
1144 memset( pTM, 0, sizeof(*pTM) );
1146 #define plf ((LPLOGFONT16)pLF)
1147 plf->lfHeight = pTM->tmHeight = pfi->df.dfPixHeight;
1148 plf->lfWidth = pTM->tmAveCharWidth = pfi->df.dfAvgWidth;
1149 plf->lfWeight = pTM->tmWeight = pfi->df.dfWeight;
1150 plf->lfItalic = pTM->tmItalic = pfi->df.dfItalic;
1151 plf->lfUnderline = pTM->tmUnderlined = pfi->df.dfUnderline;
1152 plf->lfStrikeOut = pTM->tmStruckOut = pfi->df.dfStrikeOut;
1153 plf->lfCharSet = pTM->tmCharSet = pfi->df.dfCharSet;
1155 /* convert pitch values */
1157 pTM->tmPitchAndFamily = pfi->df.dfPitchAndFamily;
1158 plf->lfPitchAndFamily = (pfi->df.dfPitchAndFamily & 0xF1) + 1;
1160 lstrcpynA( plf->lfFaceName, pfi->df.dfFace, LF_FACESIZE );
1161 #undef plf
1163 /* FIXME: fill in rest of plF values
1164 lstrcpynA(plF->elfFullName, , LF_FULLFACESIZE);
1165 lstrcpynA(plF->elfStyle, , LF_FACESIZE);
1166 lstrcpynA(plF->elfScript, , LF_FACESIZE);
1169 pTM->tmAscent = pfi->df.dfAscent;
1170 pTM->tmDescent = pTM->tmHeight - pTM->tmAscent;
1171 pTM->tmInternalLeading = pfi->df.dfInternalLeading;
1172 pTM->tmMaxCharWidth = pfi->df.dfMaxWidth;
1173 pTM->tmDigitizedAspectX = pfi->df.dfHorizRes;
1174 pTM->tmDigitizedAspectY = pfi->df.dfVertRes;
1176 pTM->tmFirstChar = pfi->df.dfFirstChar;
1177 pTM->tmLastChar = pfi->df.dfLastChar;
1178 pTM->tmDefaultChar = pfi->df.dfDefaultChar;
1179 pTM->tmBreakChar = pfi->df.dfBreakChar;
1181 /* return font type */
1183 return pfi->df.dfType;
1187 /***********************************************************************
1188 * XFONT_FixupFlags
1190 * INIT ONLY
1192 * dfPitchAndFamily flags for some common typefaces.
1194 static BYTE XFONT_FixupFlags( LPCSTR lfFaceName )
1196 switch( lfFaceName[0] )
1198 case 'a':
1199 case 'A': if(!strncasecmp(lfFaceName, "Arial", 5) )
1200 return FF_SWISS;
1201 break;
1202 case 'h':
1203 case 'H': if(!strcasecmp(lfFaceName, "Helvetica") )
1204 return FF_SWISS;
1205 break;
1206 case 'c':
1207 case 'C': if(!strncasecmp(lfFaceName, "Courier", 7))
1208 return FF_MODERN;
1210 if (!strcasecmp(lfFaceName, "Charter") )
1211 return FF_ROMAN;
1212 break;
1213 case 'p':
1214 case 'P': if( !strcasecmp(lfFaceName,"Palatino") )
1215 return FF_ROMAN;
1216 break;
1217 case 't':
1218 case 'T': if(!strncasecmp(lfFaceName, "Times", 5) )
1219 return FF_ROMAN;
1220 break;
1221 case 'u':
1222 case 'U': if(!strcasecmp(lfFaceName, "Utopia") )
1223 return FF_ROMAN;
1224 break;
1225 case 'z':
1226 case 'Z': if(!strcasecmp(lfFaceName, "Zapf Dingbats") )
1227 return FF_DECORATIVE;
1229 return 0;
1232 /***********************************************************************
1233 * XFONT_SameFoundryAndFamily
1235 * INIT ONLY
1237 static BOOL XFONT_SameFoundryAndFamily( const LFD* lfd1, const LFD* lfd2 )
1239 return ( !strcasecmp( lfd1->foundry, lfd2->foundry ) &&
1240 !strcasecmp( lfd1->family, lfd2->family ) );
1243 /***********************************************************************
1244 * XFONT_InitialCapitals
1246 * INIT ONLY
1248 * Upper case first letters of words & remove multiple spaces
1250 static void XFONT_InitialCapitals(LPSTR lpch)
1252 int i;
1253 BOOL up;
1254 char* lpstr = lpch;
1256 for( i = 0, up = TRUE; *lpch; lpch++, i++ )
1258 if( isspace(*lpch) )
1260 if (!up) /* Not already got one */
1262 *lpstr++ = ' ';
1263 up = TRUE;
1266 else if( isalpha(*lpch) && up )
1268 *lpstr++ = toupper(*lpch);
1269 up = FALSE;
1271 else
1273 *lpstr++ = *lpch;
1274 up = FALSE;
1278 /* Remove possible trailing space */
1279 if (up && i > 0)
1280 --lpstr;
1281 *lpstr = '\0';
1285 /***********************************************************************
1286 * XFONT_WindowsNames
1288 * INIT ONLY
1290 * Build generic Windows aliases for X font names.
1292 * -misc-fixed- -> "Fixed"
1293 * -sony-fixed- -> "Sony Fixed", etc...
1295 static void XFONT_WindowsNames(void)
1297 fontResource* fr;
1299 for( fr = fontList; fr ; fr = fr->next )
1301 fontResource* pfr;
1302 char* lpch;
1304 if( fr->fr_flags & FR_NAMESET ) continue; /* skip already assigned */
1306 for( pfr = fontList; pfr != fr ; pfr = pfr->next )
1307 if( pfr->fr_flags & FR_NAMESET )
1309 if (!strcasecmp( pfr->resource->family, fr->resource->family))
1310 break;
1313 lpch = fr->lfFaceName;
1314 snprintf( fr->lfFaceName, sizeof(fr->lfFaceName), "%s %s",
1315 /* prepend vendor name */
1316 (pfr==fr) ? "" : fr->resource->foundry,
1317 fr->resource->family);
1318 XFONT_InitialCapitals(fr->lfFaceName);
1320 BYTE bFamilyStyle = XFONT_FixupFlags( fr->lfFaceName );
1321 if( bFamilyStyle)
1323 fontInfo* fi;
1324 for( fi = fr->fi ; fi ; fi = fi->next )
1325 fi->df.dfPitchAndFamily |= bFamilyStyle;
1329 TRACE("typeface '%s'\n", fr->lfFaceName);
1331 fr->fr_flags |= FR_NAMESET;
1335 /***********************************************************************
1336 * XFONT_LoadDefaultLFD
1338 * Move lfd to the head of fontList to make it more likely to be matched
1340 static void XFONT_LoadDefaultLFD(LFD* lfd, LPCSTR fonttype)
1343 fontResource *fr, *pfr;
1344 for( fr = NULL, pfr = fontList; pfr; pfr = pfr->next )
1346 if( XFONT_SameFoundryAndFamily(pfr->resource, lfd) )
1348 if( fr )
1350 fr->next = pfr->next;
1351 pfr->next = fontList;
1352 fontList = pfr;
1354 break;
1356 fr = pfr;
1358 if (!pfr)
1359 WARN("Default %sfont '-%s-%s-' not available\n", fonttype,
1360 lfd->foundry, lfd->family);
1364 /***********************************************************************
1365 * XFONT_LoadDefault
1367 static void XFONT_LoadDefault(LPCSTR ini, LPCSTR fonttype)
1369 char buffer[MAX_LFD_LENGTH];
1371 if( PROFILE_GetWineIniString( INIFontSection, ini, "", buffer, sizeof buffer ) )
1373 if (*buffer)
1375 LFD* lfd;
1376 char* pch = buffer;
1377 while( *pch && isspace(*pch) ) pch++;
1379 TRACE("Using '%s' as default %sfont\n", pch, fonttype);
1380 lfd = LFD_Parse(pch);
1381 if (lfd && lfd->foundry && lfd->family)
1382 XFONT_LoadDefaultLFD(lfd, fonttype);
1383 else
1384 WARN("Ini section [%s]%s is malformed\n", INIFontSection, ini);
1385 HeapFree(GetProcessHeap(), 0, lfd);
1390 /***********************************************************************
1391 * XFONT_LoadDefaults
1393 static void XFONT_LoadDefaults(void)
1395 XFONT_LoadDefault(INIDefaultFixed, "fixed ");
1396 XFONT_LoadDefault(INIDefault, "");
1399 /***********************************************************************
1400 * XFONT_CreateAlias
1402 static fontAlias* XFONT_CreateAlias( LPCSTR lpTypeFace, LPCSTR lpAlias )
1404 int j;
1405 fontAlias *pfa, *prev = NULL;
1407 for(pfa = aliasTable; pfa; pfa = pfa->next)
1409 /* check if we already got one */
1410 if( !strcasecmp( pfa->faTypeFace, lpAlias ) )
1412 TRACE("redundant alias '%s' -> '%s'\n",
1413 lpAlias, lpTypeFace );
1414 return NULL;
1416 prev = pfa;
1419 j = strlen(lpTypeFace) + 1;
1420 pfa = HeapAlloc( GetProcessHeap(), 0, sizeof(fontAlias) +
1421 j + strlen(lpAlias) + 1 );
1422 if (pfa)
1424 if (!prev)
1425 aliasTable = pfa;
1426 else
1427 prev->next = pfa;
1429 pfa->next = NULL;
1430 pfa->faTypeFace = (LPSTR)(pfa + 1);
1431 lstrcpyA( pfa->faTypeFace, lpTypeFace );
1432 pfa->faAlias = pfa->faTypeFace + j;
1433 lstrcpyA( pfa->faAlias, lpAlias );
1435 TRACE("added alias '%s' for '%s'\n", lpAlias, lpTypeFace );
1437 return pfa;
1439 return NULL;
1443 /***********************************************************************
1444 * XFONT_LoadAlias
1446 static void XFONT_LoadAlias(const LFD* lfd, LPCSTR lpAlias, BOOL bSubst)
1448 fontResource *fr, *frMatch = NULL;
1449 if (!lfd->foundry || ! lfd->family)
1451 WARN("Malformed font resource for alias '%s'\n", lpAlias);
1452 return;
1454 for (fr = fontList; fr ; fr = fr->next)
1456 if(!strcasecmp(fr->resource->family, lpAlias))
1458 /* alias is not needed since the real font is present */
1459 TRACE("Ignoring font alias '%s' as it is already available as a real font\n", lpAlias);
1460 return;
1462 if( XFONT_SameFoundryAndFamily( fr->resource, lfd ) )
1464 frMatch = fr;
1465 break;
1469 if( frMatch )
1471 if( bSubst )
1473 fontAlias *pfa, *prev = NULL;
1475 for(pfa = aliasTable; pfa; pfa = pfa->next)
1477 /* Remove lpAlias from aliasTable - we should free the old entry */
1478 if(!strcmp(lpAlias, pfa->faAlias))
1480 if(prev)
1481 prev->next = pfa->next;
1482 else
1483 aliasTable = pfa->next;
1486 /* Update any references to the substituted font in aliasTable */
1487 if(!strcmp(frMatch->lfFaceName, pfa->faTypeFace))
1488 pfa->faTypeFace = HEAP_strdupA( GetProcessHeap(), 0, lpAlias );
1489 prev = pfa;
1492 TRACE("\tsubstituted '%s' with '%s'\n", frMatch->lfFaceName, lpAlias );
1494 lstrcpynA( frMatch->lfFaceName, lpAlias, LF_FACESIZE );
1495 frMatch->fr_flags |= FR_NAMESET;
1497 else
1499 /* create new entry in the alias table */
1500 XFONT_CreateAlias( frMatch->lfFaceName, lpAlias );
1503 else
1505 WARN("Font alias '-%s-%s-' is not available\n", lfd->foundry, lfd->family);
1509 /***********************************************************************
1510 * XFONT_LoadAliases
1512 * INIT ONLY
1514 * Create font aliases for some standard windows fonts using user's
1515 * default choice of (sans-)serif fonts
1517 * Read user-defined aliases from wine.conf. Format is as follows
1519 * Alias# = [Windows font name],[LFD font name], <substitute original name>
1521 * Example:
1522 * Alias0 = Arial, -adobe-helvetica-
1523 * Alias1 = Times New Roman, -bitstream-courier-, 1
1524 * ...
1526 * Note that from 970817 and on we have built-in alias templates that take
1527 * care of the necessary Windows typefaces.
1529 typedef struct
1531 LPSTR fatResource;
1532 LPSTR fatAlias;
1533 } aliasTemplate;
1535 static void XFONT_LoadAliases(void)
1537 char *lpResource;
1538 char buffer[MAX_LFD_LENGTH];
1539 int i = 0;
1540 LFD* lfd;
1542 /* built-ins first */
1543 PROFILE_GetWineIniString( INIFontSection, INIDefaultSerif,
1544 "-bitstream-charter-", buffer, sizeof buffer );
1545 TRACE("Using '%s' as default serif font\n", buffer);
1546 lfd = LFD_Parse(buffer);
1547 /* NB XFONT_InitialCapitals should not change these standard aliases */
1548 if (lfd)
1550 XFONT_LoadAlias( lfd, "Tms Roman", FALSE);
1551 XFONT_LoadAlias( lfd, "MS Serif", FALSE);
1552 XFONT_LoadAlias( lfd, "Times New Roman", FALSE);
1554 XFONT_LoadDefaultLFD( lfd, "serif ");
1555 HeapFree(GetProcessHeap(), 0, lfd);
1558 PROFILE_GetWineIniString( INIFontSection, INIDefaultSansSerif,
1559 "-adobe-helvetica-", buffer, sizeof buffer);
1560 TRACE("Using '%s' as default sans serif font\n", buffer);
1561 lfd = LFD_Parse(buffer);
1562 if (lfd)
1564 XFONT_LoadAlias( lfd, "Helv", FALSE);
1565 XFONT_LoadAlias( lfd, "MS Sans Serif", FALSE);
1566 XFONT_LoadAlias( lfd, "Arial", FALSE);
1568 XFONT_LoadDefaultLFD( lfd, "sans serif ");
1569 HeapFree(GetProcessHeap(), 0, lfd);
1572 /* then user specified aliases */
1575 BOOL bHaveAlias, bSubst;
1576 char subsection[32];
1577 snprintf( subsection, sizeof subsection, "%s%i", INIAliasSection, i++ );
1579 bHaveAlias = PROFILE_GetWineIniString( INIFontSection,
1580 subsection, "", buffer, sizeof buffer);
1581 if (!bHaveAlias)
1582 break;
1584 XFONT_InitialCapitals(buffer);
1585 lpResource = PROFILE_GetStringItem( buffer );
1586 bSubst = (PROFILE_GetStringItem( lpResource )) ? TRUE : FALSE;
1587 if( lpResource && *lpResource )
1589 lfd = LFD_Parse(lpResource);
1590 if (lfd)
1592 XFONT_LoadAlias(lfd, buffer, bSubst);
1593 HeapFree(GetProcessHeap(), 0, lfd);
1596 else
1597 WARN("malformed font alias '%s'\n", buffer );
1599 while(TRUE);
1602 /***********************************************************************
1603 * XFONT_UnAlias
1605 * Convert an (potential) alias into a real windows name
1608 static LPCSTR XFONT_UnAlias(char* font)
1610 if (font[0])
1612 fontAlias* fa;
1613 XFONT_InitialCapitals(font); /* to remove extra white space */
1615 for( fa = aliasTable; fa; fa = fa->next )
1616 /* use case insensitive matching to handle eg "MS Sans Serif" */
1617 if( !strcasecmp( fa->faAlias, font ) )
1619 TRACE("found alias '%s'->%s'\n", font, fa->faTypeFace );
1620 strcpy(font, fa->faTypeFace);
1621 return fa->faAlias;
1622 break;
1625 return NULL;
1628 /***********************************************************************
1629 * XFONT_RemoveFontResource
1631 * Caller should check if the font resource is in use. If it is it should
1632 * set FR_REMOVED flag to delay removal until the resource is not in use
1633 * any more.
1635 void XFONT_RemoveFontResource( fontResource** ppfr )
1637 fontResource* pfr = *ppfr;
1638 #if 0
1639 fontInfo* pfi;
1641 /* FIXME - if fonts were read from a cache, these HeapFrees will fail */
1642 while( pfr->fi )
1644 pfi = pfr->fi->next;
1645 HeapFree( GetProcessHeap(), 0, pfr->fi );
1646 pfr->fi = pfi;
1648 HeapFree( GetProcessHeap(), 0, pfr );
1649 #endif
1650 *ppfr = pfr->next;
1653 /***********************************************************************
1654 * XFONT_LoadIgnores
1656 * INIT ONLY
1658 * Removes specified fonts from the font table to prevent Wine from
1659 * using it.
1661 * Ignore# = [LFD font name]
1663 * Example:
1664 * Ignore0 = -misc-nil-
1665 * Ignore1 = -sun-open look glyph-
1666 * ...
1669 static void XFONT_LoadIgnore(char* lfdname)
1671 fontResource** ppfr;
1673 LFD* lfd = LFD_Parse(lfdname);
1674 if (lfd && lfd->foundry && lfd->family)
1676 for( ppfr = &fontList; *ppfr ; ppfr = &((*ppfr)->next))
1678 if( XFONT_SameFoundryAndFamily( (*ppfr)->resource, lfd) )
1680 TRACE("Ignoring '-%s-%s-'\n",
1681 (*ppfr)->resource->foundry, (*ppfr)->resource->family );
1683 XFONT_RemoveFontResource( ppfr );
1684 break;
1688 else
1689 WARN("Malformed font resource\n");
1691 HeapFree(GetProcessHeap(), 0, lfd);
1694 static void XFONT_LoadIgnores(void)
1696 int i = 0;
1697 char subsection[32];
1698 char buffer[MAX_LFD_LENGTH];
1700 /* Standard one that noone wants */
1701 strcpy(buffer, "-misc-nil-");
1702 XFONT_LoadIgnore(buffer);
1704 /* Others from INI file */
1707 sprintf( subsection, "%s%i", INIIgnoreSection, i++ );
1709 if( PROFILE_GetWineIniString( INIFontSection,
1710 subsection, "", buffer, sizeof buffer) )
1712 char* pch = buffer;
1713 while( *pch && isspace(*pch) ) pch++;
1714 XFONT_LoadIgnore(pch);
1716 else
1717 break;
1718 } while(TRUE);
1722 /***********************************************************************
1723 * XFONT_UserMetricsCache
1725 * Returns expanded name for the cachedmetrics file.
1726 * Now it also appends the current value of the $DISPLAY variable.
1728 static char* XFONT_UserMetricsCache( char* buffer, int* buf_size )
1730 const char *confdir = get_config_dir();
1731 const char *display_name = Options.display;
1732 int len = strlen(confdir) + strlen(INIFontMetrics) + strlen(display_name) + 2;
1734 if ((len > *buf_size) &&
1735 !(buffer = HeapReAlloc( GetProcessHeap(), 0, buffer, *buf_size = len )))
1737 ERR("out of memory\n");
1738 ExitProcess(1);
1741 sprintf( buffer, "%s/%s%s", confdir, INIFontMetrics, display_name );
1742 return buffer;
1746 /***********************************************************************
1747 * X Font Matching
1749 * Compare two fonts (only parameters set by the XFONT_InitFontInfo()).
1751 static INT XFONT_IsSubset(const fontInfo* match, const fontInfo* fi)
1753 INT m;
1755 /* 0 - keep both, 1 - keep match, -1 - keep fi */
1757 /* Compare dfItalic, Underline, Strikeout, Weight, Charset */
1758 m = (BYTE*)&fi->df.dfPixWidth - (BYTE*)&fi->df.dfItalic;
1759 if( memcmp(&match->df.dfItalic, &fi->df.dfItalic, m )) return 0;
1761 if( (!((fi->fi_flags & FI_SCALABLE) + (match->fi_flags & FI_SCALABLE))
1762 && fi->lfd_height != match->lfd_height) ||
1763 (!((fi->fi_flags & FI_POLYWEIGHT) + (match->fi_flags & FI_POLYWEIGHT))
1764 && fi->df.dfWeight != match->df.dfWeight) ) return 0;
1766 m = (int)(match->fi_flags & (FI_POLYWEIGHT | FI_SCALABLE)) -
1767 (int)(fi->fi_flags & (FI_SCALABLE | FI_POLYWEIGHT));
1769 if( m == (FI_POLYWEIGHT - FI_SCALABLE) ||
1770 m == (FI_SCALABLE - FI_POLYWEIGHT) ) return 0; /* keep both */
1771 else if( m >= 0 ) return 1; /* 'match' is better */
1773 return -1; /* 'fi' is better */
1776 /***********************************************************************
1777 * XFONT_CheckFIList
1779 * REMOVE_SUBSETS - attach new fi and purge subsets
1780 * UNMARK_SUBSETS - remove subset flags from all fi entries
1782 static void XFONT_CheckFIList( fontResource* fr, fontInfo* fi, int action)
1784 int i = 0;
1785 fontInfo* pfi, *prev;
1787 for( prev = NULL, pfi = fr->fi; pfi; )
1789 if( action == REMOVE_SUBSETS )
1791 if( pfi->fi_flags & FI_SUBSET )
1793 fontInfo* subset = pfi;
1795 i++;
1796 fr->fi_count--;
1797 if( prev ) prev->next = pfi = pfi->next;
1798 else fr->fi = pfi = pfi->next;
1799 HeapFree( GetProcessHeap(), 0, subset );
1800 continue;
1803 else pfi->fi_flags &= ~FI_SUBSET;
1805 prev = pfi;
1806 pfi = pfi->next;
1809 if( action == REMOVE_SUBSETS ) /* also add the superset */
1811 if( fi->fi_flags & FI_SCALABLE )
1813 fi->next = fr->fi;
1814 fr->fi = fi;
1816 else if( prev ) prev->next = fi; else fr->fi = fi;
1817 fr->fi_count++;
1820 if( i ) TRACE("\t purged %i subsets [%i]\n", i , fr->fi_count);
1823 /***********************************************************************
1824 * XFONT_FindFIList
1826 static fontResource* XFONT_FindFIList( fontResource* pfr, const char* pTypeFace )
1828 while( pfr )
1830 if( !strcasecmp( pfr->lfFaceName, pTypeFace ) ) break;
1831 pfr = pfr->next;
1833 /* Give the app back the font name it asked for. Encarta checks this. */
1834 if (pfr) strcpy(pfr->lfFaceName,pTypeFace);
1835 return pfr;
1838 /***********************************************************************
1839 * XFONT_FixupPointSize
1841 static void XFONT_FixupPointSize(fontInfo* fi)
1843 #define df (fi->df)
1844 df.dfHorizRes = df.dfVertRes = fi->lfd_resolution;
1845 df.dfPoints = (INT16)
1846 (((INT)(df.dfPixHeight - df.dfInternalLeading) * 72 + (df.dfVertRes >> 1)) /
1847 df.dfVertRes );
1848 #undef df
1851 /***********************************************************************
1852 * XFONT_BuildMetrics
1854 * Build font metrics from X font
1856 static int XFONT_BuildMetrics(char** x_pattern, int res, unsigned x_checksum, int x_count)
1858 int i;
1859 fontInfo* fi = NULL;
1860 fontResource* fr, *pfr;
1861 int n_ff = 0;
1863 MESSAGE("Building font metrics. This may take some time...\n");
1864 for( i = 0; i < x_count; i++ )
1866 char* typeface;
1867 LFD* lfd;
1868 int j;
1869 char buffer[MAX_LFD_LENGTH];
1870 char* lpstr;
1871 XFontStruct* x_fs;
1872 fontInfo* pfi;
1874 typeface = HEAP_strdupA(GetProcessHeap(), 0, x_pattern[i]);
1875 if (!typeface)
1876 break;
1878 lfd = LFD_Parse(typeface);
1879 if (!lfd)
1881 HeapFree(GetProcessHeap(), 0, typeface);
1882 continue;
1885 /* find a family to insert into */
1887 for( pfr = NULL, fr = fontList; fr; fr = fr->next )
1889 if( XFONT_SameFoundryAndFamily(fr->resource, lfd))
1890 break;
1891 pfr = fr;
1894 if( !fi ) fi = (fontInfo*) HeapAlloc(GetProcessHeap(), 0, sizeof(fontInfo));
1896 if( !LFD_InitFontInfo( fi, lfd, x_pattern[i]) )
1897 goto nextfont;
1899 if( !fr ) /* add new family */
1901 n_ff++;
1902 fr = (fontResource*) HeapAlloc(GetProcessHeap(), 0, sizeof(fontResource));
1903 if (fr)
1905 memset(fr, 0, sizeof(fontResource));
1907 fr->resource = (LFD*) HeapAlloc(GetProcessHeap(), 0, sizeof(LFD));
1908 memset(fr->resource, 0, sizeof(LFD));
1910 TRACE("family: -%s-%s-\n", lfd->foundry, lfd->family );
1911 fr->resource->foundry = HEAP_strdupA(GetProcessHeap(), 0, lfd->foundry);
1912 fr->resource->family = HEAP_strdupA(GetProcessHeap(), 0, lfd->family);
1913 fr->resource->weight = "";
1915 if( pfr ) pfr->next = fr;
1916 else fontList = fr;
1918 else
1919 WARN("Not enough memory for a new font family\n");
1922 /* check if we already have something better than "fi" */
1924 for( pfi = fr->fi, j = 0; pfi && j <= 0; pfi = pfi->next )
1925 if( (j = XFONT_IsSubset( pfi, fi )) < 0 )
1926 pfi->fi_flags |= FI_SUBSET; /* superseded by "fi" */
1927 if( j > 0 ) goto nextfont;
1929 /* add new font instance "fi" to the "fr" font resource */
1931 if( fi->fi_flags & FI_SCALABLE )
1933 LFD lfd1;
1934 char pxl_string[4], res_string[4];
1935 /* set scalable font height to get an basis for extrapolation */
1937 fi->lfd_height = DEF_SCALABLE_HEIGHT;
1938 fi->lfd_resolution = res;
1940 sprintf(pxl_string, "%d", fi->lfd_height);
1941 sprintf(res_string, "%d", fi->lfd_resolution);
1943 lfd1 = *lfd;
1944 lfd1.pixel_size = pxl_string;
1945 lfd1.point_size = "*";
1946 lfd1.resolution_x = res_string;
1947 lfd1.resolution_y = res_string;
1949 LFD_UnParse(buffer, sizeof buffer, &lfd1);
1951 lpstr = buffer;
1953 else lpstr = x_pattern[i];
1955 if( (x_fs = TSXLoadQueryFont(display, lpstr)) )
1957 XFONT_SetFontMetric( fi, fr, x_fs );
1958 TSXFreeFont( display, x_fs );
1960 XFONT_FixupPointSize(fi);
1962 TRACE("\t[% 2ipt] '%s'\n", fi->df.dfPoints, x_pattern[i] );
1964 XFONT_CheckFIList( fr, fi, REMOVE_SUBSETS );
1965 fi = NULL; /* preventing reuse */
1967 else
1969 ERR("failed to load %s\n", lpstr );
1971 XFONT_CheckFIList( fr, fi, UNMARK_SUBSETS );
1973 nextfont:
1974 HeapFree(GetProcessHeap(), 0, lfd);
1975 HeapFree(GetProcessHeap(), 0, typeface);
1977 if( fi ) HeapFree(GetProcessHeap(), 0, fi);
1979 /* Scan through the font list and remove FontResorce(s) (fr)
1980 * that have no associated Fontinfo(s) (fi).
1981 * This code is necessary because XFONT_ReadCachedMetrics
1982 * assumes that there is at least one fi associated with a fr.
1983 * This assumption is invalid for TT font
1984 * -altsys-ms outlook-medium-r-normal--0-0-0-0-p-0-microsoft-symbol.
1987 fr = fontList;
1989 while (!fr->fi_count)
1991 fontList = fr->next;
1993 HeapFree(GetProcessHeap(), 0, fr->resource);
1994 HeapFree(GetProcessHeap(), 0, fr);
1996 fr = fontList;
1997 n_ff--;
2000 fr = fontList;
2002 while (fr->next)
2004 if (!fr->next->fi_count)
2006 pfr = fr->next;
2007 fr->next = fr->next->next;
2009 HeapFree(GetProcessHeap(), 0, pfr->resource);
2010 HeapFree(GetProcessHeap(), 0, pfr);
2012 n_ff--;
2014 else
2015 fr = fr->next;
2018 return n_ff;
2021 /***********************************************************************
2022 * XFONT_ReadCachedMetrics
2024 * INIT ONLY
2026 static BOOL XFONT_ReadCachedMetrics( int fd, int res, unsigned x_checksum, int x_count )
2028 if( fd >= 0 )
2030 unsigned u;
2031 int i, j;
2033 /* read checksums */
2034 read( fd, &u, sizeof(unsigned) );
2035 read( fd, &i, sizeof(int) );
2037 if( u == x_checksum && i == x_count )
2039 off_t length, offset = 3 * sizeof(int);
2041 /* read total size */
2042 read( fd, &i, sizeof(int) );
2043 length = lseek( fd, 0, SEEK_END );
2045 if( length == (i + offset) )
2047 lseek( fd, offset, SEEK_SET );
2048 fontList = (fontResource*)HeapAlloc( GetProcessHeap(), 0, i);
2049 if( fontList )
2051 fontResource* pfr = fontList;
2052 fontInfo* pfi = NULL;
2054 TRACE("Reading cached font metrics:\n");
2056 read( fd, fontList, i); /* read all metrics at once */
2057 while( offset < length )
2059 offset += sizeof(fontResource) + sizeof(fontInfo);
2060 pfr->fi = pfi = (fontInfo*)(pfr + 1);
2061 j = 1;
2062 while( TRUE )
2064 if( offset > length ||
2065 (int)(pfi->next) != j++ ) goto fail;
2067 if( pfi->df.dfPixHeight == 0 ) goto fail;
2069 pfi->df.dfFace = pfr->lfFaceName;
2070 if( pfi->fi_flags & FI_SCALABLE )
2072 /* we can pretend we got this font for any resolution */
2073 pfi->lfd_resolution = res;
2074 XFONT_FixupPointSize(pfi);
2076 pfi->next = pfi + 1;
2078 if( j > pfr->fi_count ) break;
2080 pfi = pfi->next;
2081 offset += sizeof(fontInfo);
2083 pfi->next = NULL;
2084 if( pfr->next )
2086 pfr->next = (fontResource*)(pfi + 1);
2087 pfr = pfr->next;
2089 else break;
2091 if( pfr->next == NULL &&
2092 *(int*)(pfi + 1) == X_FMC_MAGIC )
2094 /* read LFD stubs */
2095 char* lpch = (char*)((int*)(pfi + 1) + 1);
2096 offset += sizeof(int);
2097 for( pfr = fontList; pfr; pfr = pfr->next )
2099 size_t len = strlen(lpch) + 1;
2100 TRACE("\t%s, %i instances\n", lpch, pfr->fi_count );
2101 pfr->resource = LFD_Parse(lpch);
2102 lpch += len;
2103 offset += len;
2104 if (offset > length)
2105 goto fail;
2107 close( fd );
2108 return TRUE;
2113 fail:
2114 if( fontList ) HeapFree( GetProcessHeap(), 0, fontList );
2115 fontList = NULL;
2116 close( fd );
2118 return FALSE;
2121 /***********************************************************************
2122 * XFONT_WriteCachedMetrics
2124 * INIT ONLY
2126 static BOOL XFONT_WriteCachedMetrics( int fd, unsigned x_checksum, int x_count, int n_ff )
2128 fontResource* pfr;
2129 fontInfo* pfi;
2131 if( fd >= 0 )
2133 int i, j, k;
2134 char buffer[MAX_LFD_LENGTH];
2136 /* font metrics file:
2138 * +0000 x_checksum
2139 * +0004 x_count
2140 * +0008 total size to load
2141 * +000C prepackaged font metrics
2142 * ...
2143 * +...x X_FMC_MAGIC
2144 * +...x + 4 LFD stubs
2147 write( fd, &x_checksum, sizeof(unsigned) );
2148 write( fd, &x_count, sizeof(int) );
2150 for( j = i = 0, pfr = fontList; pfr; pfr = pfr->next )
2152 LFD_UnParse(buffer, sizeof buffer, pfr->resource);
2153 i += strlen( buffer) + 1;
2154 j += pfr->fi_count;
2156 i += n_ff * sizeof(fontResource) + j * sizeof(fontInfo) + sizeof(int);
2157 write( fd, &i, sizeof(int) );
2159 TRACE("Writing font cache:\n");
2161 for( pfr = fontList; pfr; pfr = pfr->next )
2163 fontInfo fi;
2165 TRACE("\t-%s-%s-, %i instances\n", pfr->resource->foundry, pfr->resource->family, pfr->fi_count );
2167 i = write( fd, pfr, sizeof(fontResource) );
2168 if( i == sizeof(fontResource) )
2170 for( k = 1, pfi = pfr->fi; pfi; pfi = pfi->next )
2172 fi = *pfi;
2174 fi.df.dfFace = NULL;
2175 fi.next = (fontInfo*)k; /* loader checks this */
2177 j = write( fd, &fi, sizeof(fi) );
2178 k++;
2180 if( j == sizeof(fontInfo) ) continue;
2182 break;
2184 if( i == sizeof(fontResource) && j == sizeof(fontInfo) )
2186 i = j = X_FMC_MAGIC;
2187 write( fd, &i, sizeof(int) );
2188 for( pfr = fontList; pfr && i == j; pfr = pfr->next )
2190 LFD_UnParse(buffer, sizeof buffer, pfr->resource);
2191 i = strlen( buffer ) + 1;
2192 j = write( fd, buffer, i );
2195 close( fd );
2196 return ( i == j );
2198 return FALSE;
2201 /***********************************************************************
2202 * XFONT_GetPointResolution()
2204 * INIT ONLY
2206 * Here we initialize DefResolution which is used in the
2207 * XFONT_Match() penalty function. We also load the point
2208 * resolution value (higher values result in larger fonts).
2210 static int XFONT_GetPointResolution( DeviceCaps* pDevCaps )
2212 int i, j, point_resolution, num = 3;
2213 int allowed_xfont_resolutions[3] = { 72, 75, 100 };
2214 int best = 0, best_diff = 65536;
2216 point_resolution = PROFILE_GetWineIniInt( INIFontSection, INIResolution, 0 );
2217 if( !point_resolution )
2218 point_resolution = pDevCaps->logPixelsY;
2219 else
2220 pDevCaps->logPixelsX = pDevCaps->logPixelsY = point_resolution;
2223 /* FIXME We can only really guess at a best DefResolution
2224 * - this should be configurable
2226 for( i = best = 0; i < num; i++ )
2228 j = abs( point_resolution - allowed_xfont_resolutions[i] );
2229 if( j < best_diff )
2231 best = i;
2232 best_diff = j;
2235 DefResolution = allowed_xfont_resolutions[best];
2237 /* FIXME - do win95,nt40,... do this as well ? */
2238 if (TWEAK_WineLook == WIN98_LOOK)
2240 /* Lie about the screen size, so that eg MM_LOMETRIC becomes MM_logical_LOMETRIC */
2241 int denom;
2242 denom = pDevCaps->logPixelsX * 10;
2243 pDevCaps->horzSize = (pDevCaps->horzRes * 254 + (denom>>1)) / denom;
2244 denom = pDevCaps->logPixelsY * 10;
2245 pDevCaps->vertSize = (pDevCaps->vertRes * 254 + (denom>>1)) / denom;
2248 return point_resolution;
2252 /***********************************************************************
2253 * XFONT_Match
2255 * Compute the matching score between the logical font and the device font.
2257 * contributions from highest to lowest:
2258 * charset
2259 * fixed pitch
2260 * height
2261 * family flags (only when the facename is not present)
2262 * width
2263 * weight, italics, underlines, strikeouts
2265 * NOTE: you can experiment with different penalty weights to see what happens.
2266 * http://premium.microsoft.com/msdn/library/techart/f365/f36b/f37b/d38b/sa8bf.htm
2268 static UINT XFONT_Match( fontMatch* pfm )
2270 fontInfo* pfi = pfm->pfi; /* device font to match */
2271 LPLOGFONT16 plf = pfm->plf; /* wanted logical font */
2272 UINT penalty = 0;
2273 BOOL bR6 = pfm->flags & FO_MATCH_XYINDEP; /* from TextCaps */
2274 BOOL bScale = pfi->fi_flags & FI_SCALABLE;
2275 int d = 0, height;
2277 TRACE("\t[ %-2ipt h=%-3i w=%-3i %s%s]\n", pfi->df.dfPoints,
2278 pfi->df.dfPixHeight, pfi->df.dfAvgWidth,
2279 (pfi->df.dfWeight > FW_NORMAL) ? "Bold " : "Normal ",
2280 (pfi->df.dfItalic) ? "Italic" : "" );
2282 pfm->flags &= FO_MATCH_MASK;
2284 /* Charset */
2285 if (pfi->df.dfCharSet == DEFAULT_CHARSET)
2287 /* special case(unicode font) */
2288 /* priority: unmatched charset < unicode < matched charset */
2289 penalty += 0x50;
2291 else
2293 if( plf->lfCharSet == DEFAULT_CHARSET )
2295 if (pfi->df.dfCharSet != ANSI_CHARSET)
2296 penalty += 0x200;
2298 else if (plf->lfCharSet != pfi->df.dfCharSet) penalty += 0x200;
2301 /* Height */
2302 height = -1;
2304 if( plf->lfHeight > 0 )
2306 int h = pfi->df.dfPixHeight;
2307 d = h - plf->lfHeight;
2308 height = plf->lfHeight;
2310 else
2312 int h = pfi->df.dfPixHeight - pfi->df.dfInternalLeading;
2313 if (h)
2315 d = h + plf->lfHeight;
2316 height = (-plf->lfHeight * pfi->df.dfPixHeight) / h;
2318 else
2320 ERR("PixHeight == InternalLeading\n");
2321 penalty += 0x1000; /* dont want this */
2326 if( height == 0 )
2327 pfm->height = 1; /* Very small */
2328 else if( d )
2330 if( bScale )
2331 pfm->height = height;
2332 else if( (plf->lfQuality != PROOF_QUALITY) && bR6 )
2334 if( d > 0 ) /* do not shrink raster fonts */
2336 pfm->height = pfi->df.dfPixHeight;
2337 penalty += (pfi->df.dfPixHeight - height) * 0x4;
2339 else /* expand only in integer multiples */
2341 pfm->height = height - height%pfi->df.dfPixHeight;
2342 penalty += (height - pfm->height + 1) * height / pfi->df.dfPixHeight;
2345 else /* can't be scaled at all */
2347 if( plf->lfQuality != PROOF_QUALITY) pfm->flags |= FO_SYNTH_HEIGHT;
2348 pfm->height = pfi->df.dfPixHeight;
2349 penalty += (d > 0)? d * 0x8 : -d * 0x10;
2352 else
2353 pfm->height = pfi->df.dfPixHeight;
2355 /* Pitch and Family */
2356 if( pfm->flags & FO_MATCH_PAF ) {
2357 int family = plf->lfPitchAndFamily & FF_FAMILY;
2359 /* TMPF_FIXED_PITCH means exactly the opposite */
2360 if( plf->lfPitchAndFamily & FIXED_PITCH ) {
2361 if( pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH ) penalty += 0x100;
2362 } else /* Variable is the default */
2363 if( !(pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH) ) penalty += 0x2;
2365 if (family != FF_DONTCARE && family != (pfi->df.dfPitchAndFamily & FF_FAMILY) )
2366 penalty += 0x10;
2369 /* Width */
2370 if( plf->lfWidth )
2372 int h;
2373 if( bR6 || bScale ) h = 0;
2374 else
2376 /* FIXME: not complete */
2378 pfm->flags |= FO_SYNTH_WIDTH;
2379 h = abs(plf->lfWidth - (pfm->height * pfi->df.dfAvgWidth)/pfi->df.dfPixHeight);
2381 penalty += h * ( d ) ? 0x2 : 0x1 ;
2383 else if( !(pfi->fi_flags & FI_NORMAL) ) penalty++;
2385 /* Weight */
2386 if( plf->lfWeight != FW_DONTCARE )
2388 penalty += abs(plf->lfWeight - pfi->df.dfWeight) / 40;
2389 if( plf->lfWeight > pfi->df.dfWeight ) pfm->flags |= FO_SYNTH_BOLD;
2390 } else if( pfi->df.dfWeight >= FW_BOLD ) penalty++; /* choose normal by default */
2392 /* Italic */
2393 if( plf->lfItalic != pfi->df.dfItalic )
2395 penalty += 0x4;
2396 pfm->flags |= FO_SYNTH_ITALIC;
2398 /* Underline */
2399 if( plf->lfUnderline ) pfm->flags |= FO_SYNTH_UNDERLINE;
2401 /* Strikeout */
2402 if( plf->lfStrikeOut ) pfm->flags |= FO_SYNTH_STRIKEOUT;
2405 if( penalty && !bScale && pfi->lfd_resolution != DefResolution )
2406 penalty++;
2408 TRACE(" returning %i\n", penalty );
2410 return penalty;
2413 /***********************************************************************
2414 * XFONT_MatchFIList
2416 * Scan a particular font resource for the best match.
2418 static UINT XFONT_MatchFIList( fontMatch* pfm )
2420 BOOL skipRaster = (pfm->flags & FO_MATCH_NORASTER);
2421 UINT current_score, score = (UINT)(-1);
2422 fontMatch fm = *pfm;
2424 for( fm.pfi = pfm->pfr->fi; fm.pfi && score; fm.pfi = fm.pfi->next)
2426 if( skipRaster && !(fm.pfi->fi_flags & FI_SCALABLE) )
2427 continue;
2429 current_score = XFONT_Match( &fm );
2430 if( score > current_score )
2432 *pfm = fm;
2433 score = current_score;
2436 return score;
2439 /***********************************************************************
2440 * XFONT_MatchDeviceFont
2442 * Scan font resource tree.
2445 static void XFONT_MatchDeviceFont( fontResource* start, fontMatch* pfm)
2447 fontMatch fm = *pfm;
2448 UINT current_score, score = (UINT)(-1);
2449 fontResource** ppfr;
2451 TRACE("(%u) '%s' h=%i weight=%i %s\n",
2452 pfm->plf->lfCharSet, pfm->plf->lfFaceName, pfm->plf->lfHeight,
2453 pfm->plf->lfWeight, (pfm->plf->lfItalic) ? "Italic" : "" );
2455 pfm->pfi = NULL;
2456 if( fm.plf->lfFaceName[0] )
2458 fm.pfr = XFONT_FindFIList( start, fm.plf->lfFaceName);
2459 if( fm.pfr ) /* match family */
2461 TRACE("found facename '%s'\n", fm.pfr->lfFaceName );
2463 if( fm.pfr->fr_flags & FR_REMOVED )
2464 fm.pfr = 0;
2465 else
2467 XFONT_MatchFIList( &fm );
2468 *pfm = fm;
2469 if (pfm->pfi)
2470 return;
2475 /* match all available fonts */
2477 fm.flags |= FO_MATCH_PAF;
2478 for( ppfr = &fontList; *ppfr && score; ppfr = &(*ppfr)->next )
2480 if( (*ppfr)->fr_flags & FR_REMOVED )
2482 if( (*ppfr)->fo_count == 0 )
2483 XFONT_RemoveFontResource( ppfr );
2484 continue;
2487 fm.pfr = *ppfr;
2489 TRACE("%s\n", fm.pfr->lfFaceName );
2491 current_score = XFONT_MatchFIList( &fm );
2492 if( current_score < score )
2494 score = current_score;
2495 *pfm = fm;
2501 /***********************************************************************
2502 * X Font Cache
2504 static void XFONT_GrowFreeList(int start, int end)
2506 /* add all entries from 'start' up to and including 'end' */
2508 memset( fontCache + start, 0, (end - start + 1) * sizeof(fontObject) );
2510 fontCache[end].lru = fontLF;
2511 fontCache[end].count = -1;
2512 fontLF = start;
2513 while( start < end )
2515 fontCache[start].count = -1;
2516 fontCache[start].lru = start + 1;
2517 start++;
2521 static fontObject* XFONT_LookupCachedFont( const LPLOGFONT16 plf, UINT16* checksum )
2523 UINT16 cs = __lfCheckSum( plf );
2524 int i = fontMRU, prev = -1;
2526 *checksum = cs;
2527 while( i >= 0 )
2529 if( fontCache[i].lfchecksum == cs &&
2530 !(fontCache[i].fo_flags & FO_REMOVED) )
2532 /* FIXME: something more intelligent here ? */
2534 if( !memcmp( plf, &fontCache[i].lf,
2535 sizeof(LOGFONT16) - LF_FACESIZE ) &&
2536 !strcmp( plf->lfFaceName, fontCache[i].lf.lfFaceName) )
2538 /* remove temporarily from the lru list */
2539 if( prev >= 0 )
2540 fontCache[prev].lru = fontCache[i].lru;
2541 else
2542 fontMRU = (INT16)fontCache[i].lru;
2543 return (fontCache + i);
2546 prev = i;
2547 i = (INT16)fontCache[i].lru;
2549 return NULL;
2552 static fontObject* XFONT_GetCacheEntry(void)
2554 int i;
2556 if( fontLF == -1 )
2558 int prev_i, prev_j, j;
2560 TRACE("font cache is full\n");
2562 /* lookup the least recently used font */
2564 for( prev_i = prev_j = j = -1, i = fontMRU; i >= 0; i = (INT16)fontCache[i].lru )
2566 if( fontCache[i].count <= 0 &&
2567 !(fontCache[i].fo_flags & FO_SYSTEM) )
2569 prev_j = prev_i;
2570 j = i;
2572 prev_i = i;
2575 if( j >= 0 ) /* unload font */
2577 /* detach from the lru list */
2579 TRACE("\tfreeing entry %i\n", j );
2581 fontCache[j].fr->fo_count--;
2583 if( prev_j >= 0 )
2584 fontCache[prev_j].lru = fontCache[j].lru;
2585 else fontMRU = (INT16)fontCache[j].lru;
2587 /* FIXME: lpXForm, lpPixmap */
2588 if(fontCache[j].lpX11Trans)
2589 HeapFree( GetProcessHeap(), 0, fontCache[j].lpX11Trans );
2591 TSXFreeFont( display, fontCache[j].fs );
2593 memset( fontCache + j, 0, sizeof(fontObject) );
2594 return (fontCache + j);
2596 else /* expand cache */
2598 fontObject* newCache;
2600 prev_i = fontCacheSize + FONTCACHE;
2602 TRACE("\tgrowing font cache from %i to %i\n", fontCacheSize, prev_i );
2604 if( (newCache = (fontObject*)HeapReAlloc(GetProcessHeap(), 0,
2605 fontCache, prev_i)) )
2607 i = fontCacheSize;
2608 fontCacheSize = prev_i;
2609 fontCache = newCache;
2610 XFONT_GrowFreeList( i, fontCacheSize - 1);
2612 else return NULL;
2616 /* detach from the free list */
2618 i = fontLF;
2619 fontLF = (INT16)fontCache[i].lru;
2620 fontCache[i].count = 0;
2621 return (fontCache + i);
2624 static int XFONT_ReleaseCacheEntry(const fontObject* pfo)
2626 UINT u = (UINT)(pfo - fontCache);
2628 if( u < fontCacheSize ) return (--fontCache[u].count);
2629 return -1;
2632 /***********************************************************************
2633 * X11DRV_FONT_Init
2635 * Initialize font resource list and allocate font cache.
2637 BOOL X11DRV_FONT_Init( DeviceCaps* pDevCaps )
2639 char** x_pattern;
2640 unsigned x_checksum;
2641 int i,res, x_count, fd, buf_size;
2642 char *buffer;
2644 res = XFONT_GetPointResolution( pDevCaps );
2646 x_pattern = TSXListFonts(display, "*", MAX_FONTS, &x_count );
2648 TRACE("Font Mapper: initializing %i fonts [logical dpi=%i, default dpi=%i]\n",
2649 x_count, res, DefResolution);
2650 if (x_count == MAX_FONTS)
2651 MESSAGE("There may be more fonts available - try increasing the value of MAX_FONTS\n");
2653 for( i = x_checksum = 0; i < x_count; i++ )
2655 int j;
2656 #if 0
2657 printf("%i\t: %s\n", i, x_pattern[i] );
2658 #endif
2660 j = strlen( x_pattern[i] );
2661 if( j ) x_checksum ^= __genericCheckSum( x_pattern[i], j );
2663 x_checksum |= X_PFONT_MAGIC;
2664 buf_size = 128;
2665 buffer = HeapAlloc( GetProcessHeap(), 0, buf_size );
2667 /* deal with systemwide font metrics cache */
2669 if( PROFILE_GetWineIniString( INIFontSection, INIGlobalMetrics, "", buffer, buf_size ) )
2671 fd = open( buffer, O_RDONLY );
2672 XFONT_ReadCachedMetrics(fd, DefResolution, x_checksum, x_count);
2674 if (fontList == NULL)
2676 /* try per-user */
2677 buffer = XFONT_UserMetricsCache( buffer, &buf_size );
2678 if( buffer[0] )
2680 fd = open( buffer, O_RDONLY );
2681 XFONT_ReadCachedMetrics(fd, DefResolution, x_checksum, x_count);
2685 if( fontList == NULL ) /* build metrics from scratch */
2687 int n_ff = XFONT_BuildMetrics(x_pattern, DefResolution, x_checksum, x_count);
2688 if( buffer[0] ) /* update cached metrics */
2690 fd = open( buffer, O_CREAT | O_TRUNC | O_RDWR, 0644 ); /* -rw-r--r-- */
2691 if( XFONT_WriteCachedMetrics( fd, x_checksum, x_count, n_ff ) == FALSE )
2693 WARN("Unable to write to fontcache '%s'\n", buffer);
2694 if( fd >= 0) remove( buffer ); /* couldn't write entire file */
2699 TSXFreeFontNames(x_pattern);
2701 /* check if we're dealing with X11 R6 server */
2703 XFontStruct* x_fs;
2704 strcpy(buffer, "-*-*-*-*-normal-*-[12 0 0 12]-*-72-*-*-*-iso8859-1");
2705 if( (x_fs = TSXLoadQueryFont(display, buffer)) )
2707 XTextCaps |= TC_SF_X_YINDEP;
2708 TSXFreeFont(display, x_fs);
2711 HeapFree(GetProcessHeap(), 0, buffer);
2713 XFONT_WindowsNames();
2714 XFONT_LoadAliases();
2715 XFONT_LoadDefaults();
2716 XFONT_LoadIgnores();
2718 /* fontList initialization is over, allocate X font cache */
2720 fontCache = (fontObject*) HeapAlloc(GetProcessHeap(), 0, fontCacheSize * sizeof(fontObject));
2721 XFONT_GrowFreeList(0, fontCacheSize - 1);
2723 TRACE("done!\n");
2725 /* update text caps parameter */
2727 pDevCaps->textCaps = XTextCaps;
2729 RAW_ASCENT = TSXInternAtom(display, "RAW_ASCENT", TRUE);
2730 RAW_DESCENT = TSXInternAtom(display, "RAW_DESCENT", TRUE);
2732 return TRUE;
2735 /**********************************************************************
2736 * XFONT_SetX11Trans
2738 static BOOL XFONT_SetX11Trans( fontObject *pfo )
2740 char *fontName;
2741 Atom nameAtom;
2742 LFD* lfd;
2744 TSXGetFontProperty( pfo->fs, XA_FONT, &nameAtom );
2745 fontName = TSXGetAtomName( display, nameAtom );
2746 lfd = LFD_Parse(fontName);
2747 if (!lfd)
2749 TSXFree(fontName);
2750 return FALSE;
2753 if (lfd->pixel_size[0] != '[') {
2754 HeapFree(GetProcessHeap(), 0, lfd);
2755 TSXFree(fontName);
2756 return FALSE;
2759 #define PX pfo->lpX11Trans
2761 sscanf(lfd->pixel_size, "[%f%f%f%f]", &PX->a, &PX->b, &PX->c, &PX->d);
2762 TSXFree(fontName);
2763 HeapFree(GetProcessHeap(), 0, lfd);
2765 TSXGetFontProperty( pfo->fs, RAW_ASCENT, &PX->RAW_ASCENT );
2766 TSXGetFontProperty( pfo->fs, RAW_DESCENT, &PX->RAW_DESCENT );
2768 PX->pixelsize = hypot(PX->a, PX->b);
2769 PX->ascent = PX->pixelsize / 1000.0 * PX->RAW_ASCENT;
2770 PX->descent = PX->pixelsize / 1000.0 * PX->RAW_DESCENT;
2772 TRACE("[%f %f %f %f] RA = %ld RD = %ld\n",
2773 PX->a, PX->b, PX->c, PX->d,
2774 PX->RAW_ASCENT, PX->RAW_DESCENT);
2776 #undef PX
2777 return TRUE;
2780 /***********************************************************************
2781 * X Device Font Objects
2783 static X_PHYSFONT XFONT_RealizeFont( const LPLOGFONT16 plf, LPCSTR* faceMatched)
2785 UINT16 checksum;
2786 INT index = 0;
2787 fontObject* pfo;
2789 pfo = XFONT_LookupCachedFont( plf, &checksum );
2790 if( !pfo )
2792 fontMatch fm;
2793 INT i;
2795 fm.pfr = NULL;
2796 fm.pfi = NULL;
2797 fm.height = 0;
2798 fm.flags = 0;
2799 fm.plf = plf;
2801 if( XTextCaps & TC_SF_X_YINDEP ) fm.flags = FO_MATCH_XYINDEP;
2803 /* allocate new font cache entry */
2805 if( (pfo = XFONT_GetCacheEntry()) )
2807 /* initialize entry and load font */
2808 char lpLFD[MAX_LFD_LENGTH];
2809 UINT uRelaxLevel = 0;
2811 if(abs(plf->lfHeight) > MAX_FONT_SIZE) {
2812 ERR(
2813 "plf->lfHeight = %d, Creating a 100 pixel font and rescaling metrics \n",
2814 plf->lfHeight);
2815 pfo->rescale = fabs(plf->lfHeight / 100.0);
2816 if(plf->lfHeight > 0) plf->lfHeight = 100;
2817 else plf->lfHeight = -100;
2818 } else
2819 pfo->rescale = 1.0;
2821 XFONT_MatchDeviceFont( fontList, &fm );
2822 pfo->fr = fm.pfr;
2823 pfo->fi = fm.pfi;
2824 pfo->fr->fo_count++;
2825 pfo->fo_flags = fm.flags & ~FO_MATCH_MASK;
2827 pfo->lf = *plf;
2828 pfo->lfchecksum = checksum;
2832 LFD_ComposeLFD( pfo, fm.height, lpLFD, uRelaxLevel++ );
2833 if( (pfo->fs = TSXLoadQueryFont( display, lpLFD )) ) break;
2834 } while( uRelaxLevel );
2837 if(pfo->lf.lfEscapement != 0) {
2838 pfo->lpX11Trans = HeapAlloc(GetProcessHeap(), 0, sizeof(XFONTTRANS));
2839 if(!XFONT_SetX11Trans( pfo )) {
2840 HeapFree(GetProcessHeap(), 0, pfo->lpX11Trans);
2841 pfo->lpX11Trans = NULL;
2844 XFONT_GetLeading( &pfo->fi->df, pfo->fs,
2845 &pfo->foInternalLeading, NULL, pfo->lpX11Trans );
2846 pfo->foAvgCharWidth = (INT16)XFONT_GetAvgCharWidth(&pfo->fi->df, pfo->fs, pfo->lpX11Trans );
2847 pfo->foMaxCharWidth = (INT16)XFONT_GetMaxCharWidth(pfo->fs, pfo->lpX11Trans);
2849 /* FIXME: If we've got a soft font or
2850 * there are FO_SYNTH_... flags for the
2851 * non PROOF_QUALITY request, the engine
2852 * should rasterize characters into mono
2853 * pixmaps and store them in the pfo->lpPixmap
2854 * array (pfo->fs should be updated as well).
2855 * array (pfo->fs should be updated as well).
2856 * X11DRV_ExtTextOut() must be heavily modified
2857 * to support pixmap blitting and FO_SYNTH_...
2858 * styles.
2861 pfo->lpPixmap = NULL;
2864 if( !pfo ) /* couldn't get a new entry, get one of the cached fonts */
2866 UINT current_score, score = (UINT)(-1);
2868 i = index = fontMRU;
2869 fm.flags |= FO_MATCH_PAF;
2872 pfo = fontCache + i;
2873 fm.pfr = pfo->fr; fm.pfi = pfo->fi;
2875 current_score = XFONT_Match( &fm );
2876 if( current_score < score ) index = i;
2878 i = pfo->lru;
2879 } while( i >= 0 );
2880 pfo = fontCache + index;
2881 goto END;
2885 /* attach at the head of the lru list */
2886 pfo->lru = fontMRU;
2887 index = fontMRU = (pfo - fontCache);
2889 END:
2890 pfo->count++;
2892 TRACE("physfont %i\n", index);
2893 *faceMatched = pfo->fi->df.dfFace;
2895 return (X_PHYSFONT)(X_PFONT_MAGIC | index);
2898 /***********************************************************************
2899 * XFONT_GetFontObject
2901 fontObject* XFONT_GetFontObject( X_PHYSFONT pFont )
2903 if( CHECK_PFONT(pFont) ) return __PFONT(pFont);
2904 return NULL;
2907 /***********************************************************************
2908 * XFONT_GetFontStruct
2910 XFontStruct* XFONT_GetFontStruct( X_PHYSFONT pFont )
2912 if( CHECK_PFONT(pFont) ) return __PFONT(pFont)->fs;
2913 return NULL;
2916 /***********************************************************************
2917 * XFONT_GetFontInfo
2919 LPIFONTINFO16 XFONT_GetFontInfo( X_PHYSFONT pFont )
2921 if( CHECK_PFONT(pFont) ) return &(__PFONT(pFont)->fi->df);
2922 return NULL;
2927 /* X11DRV Interface ****************************************************
2929 * Exposed via the dc->funcs dispatch table. *
2931 ***********************************************************************/
2932 /***********************************************************************
2933 * X11DRV_FONT_SelectObject
2935 HFONT X11DRV_FONT_SelectObject( DC* dc, HFONT hfont, FONTOBJ* font )
2937 HFONT hPrevFont = 0;
2938 LOGFONT16 lf;
2939 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2941 EnterCriticalSection( &crtsc_fonts_X11 );
2943 if( CHECK_PFONT(physDev->font) )
2944 XFONT_ReleaseCacheEntry( __PFONT(physDev->font) );
2946 lf = font->logfont;
2948 /* Make sure we don't change the sign when converting to device coords */
2949 /* FIXME - check that the other drivers do this correctly */
2950 if (lf.lfWidth)
2952 int vpt = abs(dc->vportExtX);
2953 int wnd = abs(dc->wndExtX);
2954 lf.lfWidth = (abs(lf.lfWidth) * vpt + (wnd>>1))/wnd;
2955 if (lf.lfWidth == 0)
2956 lf.lfWidth = 1; /* Minimum width */
2958 if (lf.lfHeight)
2960 int vpt = abs(dc->vportExtY);
2961 int wnd = abs(dc->wndExtY);
2962 if (lf.lfHeight > 0)
2963 lf.lfHeight = (lf.lfHeight * vpt + (wnd>>1))/wnd;
2964 else
2965 lf.lfHeight = (lf.lfHeight * vpt - (wnd>>1))/wnd;
2967 if (lf.lfHeight == 0)
2968 lf.lfHeight = MIN_FONT_SIZE;
2970 else
2971 lf.lfHeight = -(DEF_POINT_SIZE * dc->w.devCaps->logPixelsY + (72>>1)) / 72;
2974 /* Fixup aliases before passing to RealizeFont */
2975 /* alias = Windows name in the alias table */
2976 LPCSTR alias = XFONT_UnAlias( lf.lfFaceName );
2977 LPCSTR faceMatched;
2979 TRACE("hfont=%04x\n", hfont); /* to connect with the trace from RealizeFont */
2980 physDev->font = XFONT_RealizeFont( &lf, &faceMatched );
2982 /* set face to the requested facename if it matched
2983 * so that GetTextFace can get the correct face name
2985 if (alias && !strcmp(faceMatched, lf.lfFaceName))
2986 strcpy( font->logfont.lfFaceName, alias );
2987 else
2988 strcpy( font->logfont.lfFaceName, faceMatched );
2991 hPrevFont = dc->w.hFont;
2992 dc->w.hFont = hfont;
2994 LeaveCriticalSection( &crtsc_fonts_X11 );
2996 return hPrevFont;
3000 /***********************************************************************
3002 * X11DRV_EnumDeviceFonts
3004 BOOL X11DRV_EnumDeviceFonts( DC* dc, LPLOGFONT16 plf,
3005 DEVICEFONTENUMPROC proc, LPARAM lp )
3007 ENUMLOGFONTEX16 lf;
3008 NEWTEXTMETRIC16 tm;
3009 fontResource* pfr = fontList;
3010 BOOL b, bRet = 0;
3012 if( plf->lfFaceName[0] )
3014 /* enum all entries in this resource */
3015 pfr = XFONT_FindFIList( pfr, plf->lfFaceName );
3016 if( pfr )
3018 fontInfo* pfi;
3019 for( pfi = pfr->fi; pfi; pfi = pfi->next )
3021 /* Note: XFONT_GetFontMetric() will have to
3022 release the crit section, font list will
3023 have to be retraversed on return */
3025 if( (b = (*proc)( &lf, &tm,
3026 XFONT_GetFontMetric( pfi, &lf, &tm ), lp )) )
3027 bRet = b;
3028 else break;
3032 else /* enum first entry in each resource */
3033 for( ; pfr ; pfr = pfr->next )
3035 if(pfr->fi)
3037 if( (b = (*proc)( &lf, &tm,
3038 XFONT_GetFontMetric( pfr->fi, &lf, &tm ), lp )) )
3039 bRet = b;
3040 else break;
3043 return bRet;
3047 /***********************************************************************
3048 * X11DRV_GetTextMetrics
3050 BOOL X11DRV_GetTextMetrics(DC *dc, TEXTMETRICA *metrics)
3052 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
3054 if( CHECK_PFONT(physDev->font) )
3056 fontObject* pfo = __PFONT(physDev->font);
3057 XFONT_GetTextMetrics( pfo, metrics );
3059 return TRUE;
3061 return FALSE;
3065 /***********************************************************************
3066 * X11DRV_GetCharWidth
3068 BOOL X11DRV_GetCharWidth( DC *dc, UINT firstChar, UINT lastChar,
3069 LPINT buffer )
3071 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
3072 fontObject* pfo = XFONT_GetFontObject( physDev->font );
3074 if( pfo )
3076 int i;
3078 if (pfo->fs->per_char == NULL)
3079 for (i = firstChar; i <= lastChar; i++)
3080 if(pfo->lpX11Trans)
3081 *buffer++ = pfo->fs->min_bounds.attributes *
3082 pfo->lpX11Trans->pixelsize / 1000.0 * pfo->rescale;
3083 else
3084 *buffer++ = pfo->fs->min_bounds.width * pfo->rescale;
3085 else
3087 XCharStruct *cs, *def;
3088 static XCharStruct __null_char = { 0, 0, 0, 0, 0, 0 };
3090 CI_GET_CHAR_INFO(pfo->fs, pfo->fs->default_char, &__null_char,
3091 def);
3093 for (i = firstChar; i <= lastChar; i++)
3095 if (i >= pfo->fs->min_char_or_byte2 &&
3096 i <= pfo->fs->max_char_or_byte2)
3098 cs = &pfo->fs->per_char[(i - pfo->fs->min_char_or_byte2)];
3099 if (CI_NONEXISTCHAR(cs)) cs = def;
3100 } else cs = def;
3101 if(pfo->lpX11Trans)
3102 *buffer++ = max(cs->attributes, 0) *
3103 pfo->lpX11Trans->pixelsize / 1000.0 * pfo->rescale;
3104 else
3105 *buffer++ = max(cs->width, 0 ) * pfo->rescale;
3109 return TRUE;
3111 return FALSE;