XLFDs should be well-formed (14 hyphens) to match scalable fonts.
[wine.git] / graphics / x11drv / xfont.c
blob21521de1ab640fdaa541f8e8a7dd75da98324b67
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 <ctype.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <pwd.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include "ts_xlib.h"
20 #include <X11/Xatom.h>
21 #include <math.h>
22 #include <assert.h>
23 #include "heap.h"
24 #include "options.h"
25 #include "x11font.h"
26 #include "font.h"
27 #include "debug.h"
29 #define X_PFONT_MAGIC (0xFADE0000)
30 #define X_FMC_MAGIC (0x0000CAFE)
32 #define MAX_FONT_FAMILIES 128
33 #define MAX_LFD_LENGTH 256
35 #define MAX_FONT_SIZE 5000 /* Max size in pixels */
37 #define REMOVE_SUBSETS 1
38 #define UNMARK_SUBSETS 0
40 #define DEF_SCALABLE_HEIGHT 24
41 #define DEF_SCALABLE_DP 240
43 #define FF_FAMILY (FF_MODERN | FF_SWISS | FF_ROMAN | FF_DECORATIVE | FF_SCRIPT)
45 typedef struct __fontAlias
47 LPSTR faTypeFace;
48 LPSTR faAlias;
49 struct __fontAlias* next;
50 } fontAlias;
52 typedef struct
54 LPSTR fatResource;
55 LPSTR fatAlias;
56 } aliasTemplate;
58 /* Font alias table - these 2 aliases are always present */
60 static fontAlias __aliasTable[2] = {
61 { "Helvetica", "Helv", &__aliasTable[1] },
62 { "Times", "Tms Rmn", NULL }
65 static fontAlias *aliasTable = __aliasTable;
67 /* Optional built-in aliases, they are installed only when X
68 * cannot supply us with original MS fonts */
70 static int faTemplateNum = 4;
71 static aliasTemplate faTemplate[4] = {
72 { "-adobe-helvetica-", "MS Sans Serif" },
73 { "-bitstream-charter-", "MS Serif" },
74 { "-adobe-times-", "Times New Roman" },
75 { "-adobe-helvetica-", "Arial" }
78 UINT16 XTextCaps = TC_OP_CHARACTER | TC_OP_STROKE |
79 TC_CP_STROKE | TC_CR_ANY |
80 TC_SA_DOUBLE | TC_SA_INTEGER | TC_SA_CONTIN |
81 TC_UA_ABLE | TC_SO_ABLE | TC_RA_ABLE;
83 /* X11R6 adds TC_SF_X_YINDEP, maybe more... */
85 static const char* INIWinePrefix = "/.wine";
86 static const char* INIFontMetrics = "/.cachedmetrics";
87 static const char* INIFontSection = "fonts";
88 static const char* INISubSection = "Alias";
89 static const char* INIDefault = "Default";
90 static const char* INIDefaultFixed = "DefaultFixed";
91 static const char* INIResolution = "Resolution";
92 static const char* INIGlobalMetrics = "FontMetrics";
94 static const char* LFDSeparator = "*-";
95 static const char* MSEncoding = "microsoft-";
96 static const char* iso8859Encoding = "iso8859-";
97 static const char* iso646Encoding = "iso646.1991-";
98 static const char* ansiEncoding = "ansi-";
99 static unsigned DefResolution = 0;
101 static fontResource* fontList = NULL;
102 static fontObject* fontCache = NULL; /* array */
103 static int fontCacheSize = FONTCACHE;
104 static int fontLF = -1, fontMRU = -1; /* last free, most recently used */
106 #define __PFONT(pFont) ( fontCache + ((UINT32)(pFont) & 0x0000FFFF) )
107 #define CHECK_PFONT(pFont) ( (((UINT32)(pFont) & 0xFFFF0000) == X_PFONT_MAGIC) &&\
108 (((UINT32)(pFont) & 0x0000FFFF) < fontCacheSize) )
110 static INT32 XFONT_IsSubset(fontInfo*, fontInfo*);
111 static void XFONT_CheckFIList(fontResource*, fontInfo*, int subset_action);
112 static void XFONT_GrowFreeList(int start, int end);
115 static Atom RAW_ASCENT;
116 static Atom RAW_DESCENT;
118 /***********************************************************************
119 * Helper macros from X distribution
122 #define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
123 (((cs)->rbearing|(cs)->lbearing| \
124 (cs)->ascent|(cs)->descent) == 0))
126 #define CI_GET_CHAR_INFO(fs,col,def,cs) \
128 cs = def; \
129 if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
130 if (fs->per_char == NULL) { \
131 cs = &fs->min_bounds; \
132 } else { \
133 cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
134 if (CI_NONEXISTCHAR(cs)) cs = def; \
139 #define CI_GET_DEFAULT_INFO(fs,cs) \
140 CI_GET_CHAR_INFO(fs, fs->default_char, NULL, cs)
142 /***********************************************************************
143 * Checksums
145 static UINT16 __lfCheckSum( LPLOGFONT16 plf )
147 CHAR font[LF_FACESIZE];
148 UINT16 checksum = 0;
149 UINT16 i;
151 #define ptr ((UINT16*)plf)
152 for( i = 0; i < 9; i++ ) checksum ^= *ptr++;
153 #undef ptr
154 i = 0;
155 #define ptr ((CHAR*)plf)
156 do { font[i++] = tolower(*ptr++); } while (( i < LF_FACESIZE) && (*ptr) && (*ptr!=' '));
157 for( ptr = font, i >>= 1; i > 0; i-- )
158 #undef ptr
159 #define ptr ((UINT16*)plf)
160 checksum ^= *ptr++;
161 #undef ptr
162 return checksum;
165 static UINT16 __genericCheckSum( const void *ptr, int size )
167 unsigned int checksum = 0;
168 const char *p = (const char *)ptr;
169 while (size-- > 0)
170 checksum ^= (checksum << 3) + (checksum >> 29) + *p++;
172 return checksum & 0xffff;
175 /*************************************************************************
176 * LFD parse/compose routines
178 static char* LFD_Advance(LPSTR lpFont, UINT16 uParmsNo)
180 int j = 0;
181 char* lpch = lpFont;
183 for( ; j < uParmsNo && *lpch; lpch++ ) if( *lpch == LFDSeparator[1] ) j++;
184 return lpch;
187 static void LFD_GetWeight( fontInfo* fi, LPSTR lpStr, int j)
189 if( j == 1 && *lpStr == '0' )
190 fi->fi_flags |= FI_POLYWEIGHT;
191 else if( j == 4 )
193 if( !strncasecmp( "bold", lpStr, 4) )
194 fi->df.dfWeight = FW_BOLD;
195 else if( !strncasecmp( "demi", lpStr, 4) )
197 fi->fi_flags |= FI_FW_DEMI;
198 fi->df.dfWeight = FW_DEMIBOLD;
200 else if( !strncasecmp( "book", lpStr, 4) )
202 fi->fi_flags |= FI_FW_BOOK;
203 fi->df.dfWeight = FW_REGULAR;
206 else if( j == 5 )
208 if( !strncasecmp( "light", lpStr, 5) )
209 fi->df.dfWeight = FW_LIGHT;
210 else if( !strncasecmp( "black", lpStr, 5) )
211 fi->df.dfWeight = FW_BLACK;
213 else if( j == 6 && !strncasecmp( "medium", lpStr, 6) )
214 fi->df.dfWeight = FW_REGULAR;
215 else if( j == 8 && !strncasecmp( "demibold", lpStr, 8) )
216 fi->df.dfWeight = FW_DEMIBOLD;
217 else
218 fi->df.dfWeight = FW_DONTCARE; /* FIXME: try to get something
219 * from the weight property */
222 static int LFD_GetSlant( fontInfo* fi, LPSTR lpStr, int l)
224 if( l == 1 )
226 switch( tolower( *lpStr ) )
228 case '0': fi->fi_flags |= FI_POLYSLANT; /* haven't seen this one yet */
229 default:
230 case 'r': fi->df.dfItalic = 0;
231 break;
232 case 'o':
233 fi->fi_flags |= FI_OBLIQUE;
234 case 'i': fi->df.dfItalic = 1;
235 break;
237 return 0;
239 return 1;
242 /*************************************************************************
243 * LFD_InitFontInfo
245 * Fill in some fields in the fontInfo struct.
247 static int LFD_InitFontInfo( fontInfo* fi, LPSTR lpstr )
249 LPSTR lpch;
250 int i, j, dec_style_check, scalability;
251 UINT16 tmp[3];
253 memset(fi, 0, sizeof(fontInfo) );
255 /* weight name - */
256 lpch = LFD_Advance( lpstr, 1);
257 if( !*lpch ) return FALSE;
258 j = lpch - lpstr - 1;
259 LFD_GetWeight( fi, lpstr, j );
261 /* slant - */
262 lpch = LFD_Advance( lpstr = lpch, 1);
263 if( !*lpch ) return FALSE;
264 j = lpch - lpstr - 1;
265 dec_style_check = LFD_GetSlant( fi, lpstr, j );
267 /* width name - */
268 lpch = LFD_Advance( lpstr = lpch, 1);
269 if( !*lpch ) return FALSE;
270 if( strncasecmp( "normal", lpstr, 6) ) /* XXX 'narrow', 'condensed', etc... */
271 dec_style_check = TRUE;
272 else
273 fi->fi_flags |= FI_NORMAL;
275 /* style - */
276 lpch = LFD_Advance( lpstr = lpch, 1);
277 if( !*lpch ) return FALSE;
278 j = lpch - lpstr - 1;
279 if( j > 3 ) /* find out is there "sans" or "script" */
281 j = 0;
282 *(lpch - 1) = '\0';
284 if( strstr(lpstr, "sans") )
286 fi->df.dfPitchAndFamily |= FF_SWISS;
287 j = 1;
289 if( strstr(lpstr, "script") )
291 fi->df.dfPitchAndFamily |= FF_SCRIPT;
292 j = 1;
294 if( !j && dec_style_check )
295 fi->df.dfPitchAndFamily |= FF_DECORATIVE;
296 *(lpch - 1) = LFDSeparator[1];
299 /* pixel height, decipoint height, and res_x */
301 for( i = scalability = 0; i < 3; i++ )
303 lpch = LFD_Advance( lpstr = lpch, 1);
304 if( !*lpch ) return FALSE;
305 if( lpch - lpstr == 1 || lpch - lpstr > 4 ) return FALSE; /* ridiculous */
307 *(lpch - 1) = '\0';
308 if( !(tmp[i] = atoi(lpstr)) ) scalability++;
309 *(lpch - 1) = LFDSeparator[1];
311 if( scalability == 3 ) /* Type1 */
313 fi->fi_flags |= FI_SCALABLE;
314 fi->lfd_height = DEF_SCALABLE_HEIGHT; fi->lfd_decipoints = DEF_SCALABLE_DP;
315 fi->lfd_resolution = DefResolution;
317 else if( scalability == 0 ) /* Bitmap */
319 fi->lfd_height = tmp[0]; fi->lfd_decipoints = tmp[1];
320 fi->lfd_resolution = tmp[2];
322 else return FALSE; /* #$%^!!! X11R6 mutant garbage */
324 /* res_y - skip, spacing - */
325 lpstr = LFD_Advance( lpch, 1);
326 switch( *lpstr )
328 case '\0': return FALSE;
330 case 'p': fi->fi_flags |= FI_VARIABLEPITCH;
331 break;
332 case 'c': fi->df.dfPitchAndFamily |= FF_MODERN;
333 fi->fi_flags |= FI_FIXEDEX;
334 /* fall through */
335 case 'm': fi->fi_flags |= FI_FIXEDPITCH;
336 break;
337 default:
338 fi->df.dfPitchAndFamily |= DEFAULT_PITCH | FF_DONTCARE;
340 lpstr = LFD_Advance(lpstr, 1);
341 if( !*lpstr ) return FALSE;
343 /* average width - */
344 lpch = LFD_Advance( lpstr, 1);
345 if( !*lpch ) return FALSE;
346 if( lpch - lpstr == 1 || lpch - lpstr > 4 ) return FALSE; /* ridiculous */
347 *(lpch - 1) = '\0';
348 if( !(fi->lfd_width = atoi(lpstr)) && !scalability ) return FALSE;
349 *(lpch - 1) = LFDSeparator[1];
351 /* charset registry, charset encoding - */
352 if( strstr(lpch, "jisx") ||
353 strstr(lpch, "ksc") ||
354 strstr(lpch, "gb2312") ||
355 strstr(lpch, "big5") ||
356 strstr(lpch, "unicode") ) return FALSE; /* 2-byte stuff */
358 fi->df.dfCharSet = ANSI_CHARSET;
359 if( strstr(lpch, iso8859Encoding) ) {
360 fi->fi_flags |= FI_ENC_ISO8859;
361 if( strstr(lpch, "iso8859-15") ) fi->df.dfCharSet = ANSI_CHARSET;
362 else if( strstr(lpch, "iso8859-11") ) fi->df.dfCharSet = THAI_CHARSET;
363 else if( strstr(lpch, "iso8859-10") ) fi->df.dfCharSet = BALTIC_CHARSET;
364 else if( strstr(lpch, "iso8859-9") ) fi->df.dfCharSet = TURKISH_CHARSET;
365 else if( strstr(lpch, "iso8859-8") ) fi->df.dfCharSet = HEBREW_CHARSET;
366 else if( strstr(lpch, "iso8859-7") ) fi->df.dfCharSet = GREEK_CHARSET;
367 else if( strstr(lpch, "iso8859-6") ) fi->df.dfCharSet = ARABIC_CHARSET;
368 else if( strstr(lpch, "iso8859-5") ) fi->df.dfCharSet = RUSSIAN_CHARSET;
369 else if( strstr(lpch, "iso8859-4") ) fi->df.dfCharSet = ISO4_CHARSET;
370 else if( strstr(lpch, "iso8859-3") ) fi->df.dfCharSet = ISO3_CHARSET;
371 else if( strstr(lpch, "iso8859-2") ) fi->df.dfCharSet = EE_CHARSET;
372 else if( strstr(lpch, "iso8859-1") ) fi->df.dfCharSet = ANSI_CHARSET;
373 else fi->df.dfCharSet = SYMBOL_CHARSET;
374 } else if( strstr(lpch, iso646Encoding) ) {
375 fi->fi_flags |= FI_ENC_ISO646;
376 } else if( strstr(lpch, ansiEncoding) ) { /* fnt2bdf produces -ansi-0 LFD */
377 fi->fi_flags |= FI_ENC_ANSI;
378 } else { /* ... and -microsoft-cp125x */
380 fi->df.dfCharSet = OEM_CHARSET;
381 if( !strncasecmp(lpch, "microsoft-", 10) ) {
382 fi->fi_flags |= FI_ENC_MSCODEPAGE;
383 if( strstr(lpch, "-cp1250") ) fi->df.dfCharSet = EE_CHARSET;
384 else if( strstr(lpch, "-cp1251") ) fi->df.dfCharSet = RUSSIAN_CHARSET;
385 else if( strstr(lpch, "-cp1252") ) fi->df.dfCharSet = ANSI_CHARSET;
386 else if( strstr(lpch, "-cp1253") ) fi->df.dfCharSet = GREEK_CHARSET;
387 else if( strstr(lpch, "-cp1254") ) fi->df.dfCharSet = TURKISH_CHARSET;
388 else if( strstr(lpch, "-cp1255") ) fi->df.dfCharSet = HEBREW_CHARSET;
389 else if( strstr(lpch, "-cp1256") ) fi->df.dfCharSet = ARABIC_CHARSET;
390 else if( strstr(lpch, "-cp1257") ) fi->df.dfCharSet = BALTIC_CHARSET;
391 else if( strstr(lpch, "-fontspecific") ) fi->df.dfCharSet = ANSI_CHARSET;
392 else if( strstr(lpch, "-symbol") ) fi->df.dfCharSet = SYMBOL_CHARSET;
393 else fi->df.dfCharSet = SYMBOL_CHARSET;
394 } else if( !strncasecmp(lpch, "koi8-", 5) ) {
395 fi->df.dfCharSet = KOI8_CHARSET;
396 } else if( !strncasecmp(lpch, "viscii", 6) ) {
397 fi->fi_flags |= FI_ENC_ISO8859;
398 fi->df.dfCharSet = VISCII_CHARSET;
399 } else if( !strncasecmp(lpch, "tcvn-", 5) ) {
400 fi->df.dfCharSet = TCVN_CHARSET;
401 } else if( !strncasecmp(lpch, "tis620", 6) ) {
402 fi->fi_flags |= FI_ENC_ISO8859;
403 fi->df.dfCharSet = THAI_CHARSET;
404 } else if( !strncasecmp(lpch, "ascii", 5) ) {
405 fi->fi_flags |= FI_ENC_ISO646;
406 fi->df.dfCharSet = ANSI_CHARSET;
407 } else if( strstr(lpch, "fontspecific") ||
408 strstr(lpch, "microsoft-symbol") ) {
409 fi->df.dfCharSet = SYMBOL_CHARSET;
412 return TRUE;
416 /*************************************************************************
417 * LFD_ComposeLFD
419 static BOOL32 LFD_ComposeLFD( fontObject* fo,
420 INT32 height, LPSTR lpLFD, UINT32 uRelax )
422 int h, w, ch, point = 0;
423 char* lpch;
424 char lpEncoding[32];
425 char h_string[64], point_string[64];
427 *(lpLFD+MAX_LFD_LENGTH-1)=0;
428 lstrcpy32A( lpLFD, fo->fr->resource );
430 /* add weight */
431 switch( fo->fi->df.dfWeight )
433 case FW_BOLD:
434 strcat( lpLFD, "bold" ); break;
435 case FW_REGULAR:
436 if( fo->fi->fi_flags & FI_FW_BOOK )
437 strcat( lpLFD, "book" );
438 else
439 strcat( lpLFD, "medium" );
440 break;
441 case FW_DEMIBOLD:
442 strcat( lpLFD, "demi" );
443 if( !( fo->fi->fi_flags & FI_FW_DEMI) )
444 strcat ( lpLFD, "bold" );
445 break;
446 case FW_BLACK:
447 strcat( lpLFD, "black" ); break;
448 case FW_LIGHT:
449 strcat( lpLFD, "light" ); break;
450 default:
451 strcat( lpLFD, "*" );
454 /* add slant */
455 if( fo->fi->df.dfItalic )
456 if( fo->fi->fi_flags & FI_OBLIQUE )
457 strcat( lpLFD, "-o" );
458 else
459 strcat( lpLFD, "-i" );
460 else
461 strcat( lpLFD, (uRelax < 6) ? "-r" : "-*" );
463 /* add width style and skip serifs */
464 if( fo->fi->fi_flags & FI_NORMAL )
465 strcat( lpLFD, "-normal-*-");
466 else
467 strcat( lpLFD, "-*-*-" );
469 /* add pixelheight, pointheight, and resolution
471 * FIXME: fill in lpXForm and lpPixmap for rotated fonts
473 if( fo->fo_flags & FO_SYNTH_HEIGHT ) h = fo->fi->lfd_height;
474 else h = (fo->fi->lfd_height * height) / fo->fi->df.dfPixHeight;
476 if( XTextCaps & TC_SF_X_YINDEP )
478 if( fo->lf.lfWidth && !(fo->fo_flags & FO_SYNTH_WIDTH) )
479 point = (fo->fi->lfd_decipoints * fo->lf.lfWidth) / fo->fi->df.dfAvgWidth;
480 else
481 if( fo->fi->fi_flags & FI_SCALABLE ) /* adjust h/w ratio */
482 point = h * 72 * 10 / fo->fi->lfd_resolution;
485 /* handle rotated fonts */
486 if (fo->lf.lfEscapement) {
487 /* escapement is in tenths of degrees, theta is in radians */
488 double theta = M_PI*fo->lf.lfEscapement/1800.;
489 double h_matrix[4] = {h*cos(theta), h*sin(theta), -h*sin(theta), h*cos(theta)};
490 double point_matrix[4] = {point*cos(theta), point*sin(theta), -point*sin(theta), point*cos(theta)};
491 char *s;
492 sprintf(h_string, "[%+f%+f%+f%+f]", h_matrix[0], h_matrix[1], h_matrix[2], h_matrix[3]);
493 sprintf(point_string, "[%+f%+f%+f%+f]", point_matrix[0], point_matrix[1], point_matrix[2], point_matrix[3]);
494 while ((s = strchr(h_string, '-'))) *s='~';
495 while ((s = strchr(point_string, '-'))) *s='~';
496 } else {
497 sprintf(h_string, "%d", h);
498 sprintf(point_string, "%d", point);
502 /* spacing and width */
504 if( fo->fi->fi_flags & FI_FIXEDPITCH )
505 w = ( fo->fi->fi_flags & FI_FIXEDEX ) ? 'c' : 'm';
506 else
507 w = ( fo->fi->fi_flags & FI_VARIABLEPITCH ) ? 'p' : LFDSeparator[0];
509 /* encoding */
511 #define CHRS_CASE1(charset) case 0: \
512 case 3: \
513 case 6: \
514 case 9: \
515 case 12: sprintf(lpEncoding, charset ); break;
516 #define CHRS_CASE2(charset) case 1: \
517 case 4: \
518 case 7: \
519 case 10: \
520 case 13: sprintf(lpEncoding, charset ); break;
521 #define CHRS_CASE3(charset) case 2: \
522 case 5: \
523 case 8: \
524 case 11: \
525 case 14: sprintf(lpEncoding, charset ); break;
526 #define CHRS_DEF(charset) default: sprintf(lpEncoding, charset ); break;
528 if( fo->fi->df.dfCharSet == ANSI_CHARSET )
530 if( fo->fi->fi_flags & FI_ENC_ISO8859 )
531 switch (uRelax) {
532 CHRS_CASE1( "iso8859-1" );
533 CHRS_CASE2( "iso8859-1" );
534 CHRS_CASE3( "iso8859-15" );
535 CHRS_DEF( "iso8859-*" );
537 else if( fo->fi->fi_flags & FI_ENC_ISO646 )
538 switch (uRelax) {
539 CHRS_CASE1( "ascii-0" );
540 CHRS_DEF( "iso8859-1" );
542 else if( fo->fi->fi_flags & FI_ENC_MSCODEPAGE )
543 switch (uRelax) {
544 CHRS_CASE1( "microsoft-cp1252" );
545 CHRS_CASE2( "microsoft-fontspecific" );
546 CHRS_CASE3( "microsoft-cp125*" );
547 CHRS_DEF( "microsoft-*" );
549 else
550 switch (uRelax) {
551 CHRS_CASE1( "ansi-0" );
552 CHRS_CASE2( "microsoft-125*" );
553 CHRS_CASE3( "microsoft-*");
554 CHRS_DEF( "iso8859-*" );
557 else if( fo->fi->fi_flags & FI_ENC_MSCODEPAGE )
559 switch (fo->fi->df.dfCharSet) {
560 case EE_CHARSET:
561 switch (uRelax) {
562 CHRS_CASE1( "microsoft-1250" );
563 CHRS_CASE2( "iso8859-2" );
564 CHRS_DEF( "iso8859-*" );
565 } ; break;
566 case RUSSIAN_CHARSET:
567 switch (uRelax) {
568 CHRS_CASE1( "microsoft-1251" );
569 CHRS_CASE2( "iso8859-5" );
570 CHRS_CASE3( "koi8-*" );
571 CHRS_DEF( "iso8859-*" );
572 } ; break;
573 case ANSI_CHARSET:
574 switch (uRelax) {
575 CHRS_CASE1( "microsoft-1252" );
576 CHRS_CASE2( "iso8859-1" );
577 CHRS_CASE3( "iso8859-15" );
578 CHRS_DEF( "iso8859-*" );
579 } ; break;
580 case GREEK_CHARSET:
581 switch (uRelax) {
582 CHRS_CASE1( "microsoft-1253" );
583 CHRS_CASE2( "iso8859-7" );
584 CHRS_DEF( "iso8859-*" );
585 } ; break;
586 case TURKISH_CHARSET:
587 switch (uRelax) {
588 CHRS_CASE1( "microsoft-1254" );
589 CHRS_CASE2( "iso8859-9" );
590 CHRS_DEF( "iso8859-*" );
591 } ; break;
592 case HEBREW_CHARSET:
593 switch (uRelax) {
594 CHRS_CASE1( "microsoft-1255" );
595 CHRS_CASE2( "iso8859-8" );
596 CHRS_DEF( "iso8859-*" );
597 } ; break;
598 case ARABIC_CHARSET:
599 switch (uRelax) {
600 CHRS_CASE1( "microsoft-1256" );
601 CHRS_CASE2( "iso8859-6" );
602 CHRS_DEF( "iso8859-*" );
603 } ; break;
604 case BALTIC_CHARSET:
605 switch (uRelax) {
606 CHRS_CASE1( "microsoft-1257" );
607 CHRS_CASE2( "iso8859-10" );
608 CHRS_CASE3( "iso8859-15" );
609 CHRS_DEF( "iso8859-*" );
610 } ; break;
611 case THAI_CHARSET:
612 switch (uRelax) {
613 CHRS_CASE1( "iso8859-11" );
614 CHRS_CASE2( "tis620*" );
615 CHRS_DEF( "iso8859-*" );
616 } ; break;
617 case VISCII_CHARSET:
618 switch (uRelax) {
619 CHRS_CASE1( "viscii1.1-1" );
620 CHRS_CASE2( "viscii*" );
621 CHRS_DEF( "iso8859-*" );
622 } ; break;
623 case TCVN_CHARSET:
624 switch (uRelax) {
625 CHRS_CASE1( "tcvn-0" );
626 CHRS_CASE2( "tcvn*" );
627 CHRS_DEF( "iso8859-*" );
628 } ; break;
629 case KOI8_CHARSET:
630 switch (uRelax) {
631 CHRS_CASE1( "koi8-ru" );
632 CHRS_CASE2( "koi8-r" );
633 CHRS_CASE3( "koi8-*" );
634 CHRS_DEF( "iso8859-*" );
635 } ; break;
636 case ISO3_CHARSET:
637 switch (uRelax) {
638 CHRS_CASE1( "iso8859-3" );
639 CHRS_DEF( "iso8859-*" );
640 } ; break;
641 case ISO4_CHARSET:
642 switch (uRelax) {
643 CHRS_CASE1( "iso8859-4" );
644 CHRS_DEF( "iso8859-*" );
645 } ; break;
646 default:
647 switch (uRelax) {
648 CHRS_CASE1( "microsoft-symbol" );
649 CHRS_DEF( "microsoft-fontspecific" );
650 } ; break;
653 else {
654 switch (uRelax) {
655 CHRS_CASE1( "*-fontspecific" );
656 CHRS_CASE2( "*-symbol" );
657 CHRS_DEF( "*-*" ); /* whatever */
661 lpch = lpLFD + lstrlen32A(lpLFD);
662 ch = (fo->fi->fi_flags & FI_SCALABLE) ? '0' : LFDSeparator[0];
664 switch( uRelax )
666 /* RealizeFont() will call us repeatedly with increasing uRelax
667 * until XLoadFont() succeeds. */
669 case 0:
670 case 1:
671 case 2:
672 if( point )
674 sprintf( lpch, "%s-%s-%i-%c-%c-*-%s", h_string,
675 point_string,
676 fo->fi->lfd_resolution, ch, w, lpEncoding );
677 break;
679 /* fall through */
681 case 3:
682 case 4:
683 case 5:
684 case 6: /* 6-8 will have replaced an 'r' in slant by '*' */
685 case 7:
686 case 8:
687 sprintf( lpch, "%s-*-%i-%c-%c-*-%s", h_string,
688 fo->fi->lfd_resolution, ch, w, lpEncoding );
689 break;
691 case 9:
692 case 10:
693 case 11:
694 sprintf( lpch, "%s-*-%i-%c-*-*-%s",
695 h_string, fo->fi->lfd_resolution, ch, lpEncoding );
696 break;
698 case 12:
699 case 13:
700 case 14:
701 sprintf( lpch, "%i-*-%i-%c-*-*-%s", fo->fi->lfd_height,
702 fo->fi->lfd_resolution, ch, lpEncoding );
703 break;
705 case 15:
706 sprintf( lpch, "%i-*-*-*-*-*-%s", fo->fi->lfd_height, lpEncoding );
707 break;
709 default:
710 sprintf( lpch, "%i-*-*-*-*-*-*-*", fo->fi->lfd_height);
711 break;
713 /* to avoid an infinite loop; those will allways match */
714 case 200:
715 sprintf( lpLFD, "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-1" );
716 break;
717 case 201:
718 sprintf( lpLFD, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" );
719 break;
722 TRACE(font,"\tLFD(uRelax=%d): %s\n", uRelax, lpLFD );
723 assert(*(lpLFD+MAX_LFD_LENGTH-1)==0); /* check if overwrittem */
724 return TRUE;
728 /***********************************************************************
729 * X Font Resources
731 * font info - http://www.microsoft.com/kb/articles/q65/1/23.htm
732 * Windows font metrics - http://www.microsoft.com/kb/articles/q32/6/67.htm
734 static BOOL32 XFONT_GetLeading( LPIFONTINFO16 pFI, XFontStruct* x_fs, INT32*
735 pIL, INT32* pEL, XFONTTRANS *XFT )
737 unsigned long height;
738 unsigned min = (unsigned char)pFI->dfFirstChar;
739 unsigned max = (unsigned char)pFI->dfLastChar;
740 BOOL32 bHaveCapHeight = (pFI->dfCharSet == ANSI_CHARSET && 'X' >= min && 'X' <= max );
742 if( pEL ) *pEL = 0;
744 if(XFT) {
745 Atom RAW_CAP_HEIGHT = TSXInternAtom(display, "RAW_CAP_HEIGHT", TRUE);
746 if(TSXGetFontProperty(x_fs, RAW_CAP_HEIGHT, &height))
747 *pIL = XFT->ascent -
748 (INT32)(XFT->pixelsize / 1000.0 * height);
749 else
750 *pIL = 0;
751 return bHaveCapHeight && x_fs->per_char;
754 if( TSXGetFontProperty(x_fs, XA_CAP_HEIGHT, &height) == FALSE )
756 if( x_fs->per_char )
757 if( bHaveCapHeight )
758 height = x_fs->per_char['X' - min].ascent;
759 else
760 if (x_fs->ascent >= x_fs->max_bounds.ascent)
761 height = x_fs->max_bounds.ascent;
762 else
764 height = x_fs->ascent;
765 if( pEL )
766 *pEL = x_fs->max_bounds.ascent - height;
768 else
769 height = x_fs->min_bounds.ascent;
772 *pIL = x_fs->ascent - height;
773 return (bHaveCapHeight && x_fs->per_char);
776 static INT32 XFONT_GetAvgCharWidth( LPIFONTINFO16 pFI, XFontStruct* x_fs,
777 XFONTTRANS *XFT)
779 unsigned min = (unsigned char)pFI->dfFirstChar;
780 unsigned max = (unsigned char)pFI->dfLastChar;
782 if( x_fs->per_char )
784 int width, chars, j;
785 for( j = 0, width = 0, chars = 0, max -= min; j <= max; j++ )
786 if( !CI_NONEXISTCHAR(x_fs->per_char + j) )
788 if(!XFT)
789 width += x_fs->per_char[j].width;
790 else
791 width += x_fs->per_char[j].attributes *
792 XFT->pixelsize / 1000.0;
793 chars++;
795 return (width / chars);
797 /* uniform width */
798 return x_fs->min_bounds.width;
801 static INT32 XFONT_GetMaxCharWidth(fontObject *pfo)
803 unsigned min = (unsigned char)pfo->fs->min_char_or_byte2;
804 unsigned max = (unsigned char)pfo->fs->max_char_or_byte2;
806 if(!pfo->lpX11Trans)
807 return abs(pfo->fs->max_bounds.width);
809 if( pfo->fs->per_char )
811 int maxwidth, j;
812 for( j = 0, maxwidth = 0, max -= min; j <= max; j++ )
813 if( !CI_NONEXISTCHAR(pfo->fs->per_char + j) )
814 if(maxwidth < pfo->fs->per_char[j].attributes)
815 maxwidth = pfo->fs->per_char[j].attributes;
817 maxwidth *= pfo->lpX11Trans->pixelsize / 1000.0;
818 return maxwidth;
820 return pfo->foAvgCharWidth;
823 /***********************************************************************
824 * XFONT_SetFontMetric
826 * Initializes IFONTINFO16. dfHorizRes and dfVertRes must be already set.
828 static void XFONT_SetFontMetric(fontInfo* fi, fontResource* fr, XFontStruct* xfs)
830 unsigned min, max;
831 INT32 el, il;
833 fi->df.dfFirstChar = (BYTE)(min = xfs->min_char_or_byte2);
834 fi->df.dfLastChar = (BYTE)(max = xfs->max_char_or_byte2);
836 fi->df.dfDefaultChar = (BYTE)xfs->default_char;
837 fi->df.dfBreakChar = (BYTE)(( ' ' < min || ' ' > max) ? xfs->default_char: ' ');
839 fi->df.dfPixHeight = (INT16)((fi->df.dfAscent = (INT16)xfs->ascent) + xfs->descent);
840 fi->df.dfPixWidth = (xfs->per_char) ? 0 : xfs->min_bounds.width;
841 fi->df.dfMaxWidth = (INT16)abs(xfs->max_bounds.width);
843 if( XFONT_GetLeading( &fi->df, xfs, &il, &el, NULL ) )
844 fi->df.dfAvgWidth = (INT16)xfs->per_char['X' - min].width;
845 else
846 fi->df.dfAvgWidth = (INT16)XFONT_GetAvgCharWidth( &fi->df, xfs, NULL);
848 fi->df.dfInternalLeading = (INT16)il;
849 fi->df.dfExternalLeading = (INT16)el;
851 fi->df.dfPoints = (INT16)(((INT32)(fi->df.dfPixHeight -
852 fi->df.dfInternalLeading) * 72 + (fi->df.dfVertRes >> 1)) / fi->df.dfVertRes);
854 if( xfs->min_bounds.width != xfs->max_bounds.width )
855 fi->df.dfPitchAndFamily |= TMPF_FIXED_PITCH; /* au contraire! */
856 if( fi->fi_flags & FI_SCALABLE )
858 fi->df.dfType = DEVICE_FONTTYPE;
859 fi->df.dfPitchAndFamily |= TMPF_DEVICE;
861 else if( fi->fi_flags & FI_TRUETYPE )
862 fi->df.dfType = TRUETYPE_FONTTYPE;
863 else
864 fi->df.dfType = RASTER_FONTTYPE;
866 fi->df.dfFace = fr->lfFaceName;
869 /***********************************************************************
870 * XFONT_GetTextMetric
872 static void XFONT_GetTextMetric( fontObject* pfo, LPTEXTMETRIC32A pTM )
874 LPIFONTINFO16 pdf = &pfo->fi->df;
876 if( ! pfo->lpX11Trans ) {
877 pTM->tmAscent = pfo->fs->ascent;
878 pTM->tmDescent = pfo->fs->descent;
879 } else {
880 pTM->tmAscent = pfo->lpX11Trans->ascent;
881 pTM->tmDescent = pfo->lpX11Trans->descent;
883 pTM->tmHeight = pTM->tmAscent + pTM->tmDescent;
885 pTM->tmAveCharWidth = pfo->foAvgCharWidth;
886 pTM->tmMaxCharWidth = pfo->foMaxCharWidth;
888 pTM->tmInternalLeading = pfo->foInternalLeading;
889 pTM->tmExternalLeading = pdf->dfExternalLeading;
891 pTM->tmStruckOut = (pfo->fo_flags & FO_SYNTH_STRIKEOUT )
892 ? 1 : pdf->dfStrikeOut;
893 pTM->tmUnderlined = (pfo->fo_flags & FO_SYNTH_UNDERLINE )
894 ? 1 : pdf->dfUnderline;
896 pTM->tmOverhang = 0;
897 if( pfo->fo_flags & FO_SYNTH_ITALIC )
899 pTM->tmOverhang += pTM->tmHeight/3;
900 pTM->tmItalic = 1;
901 } else
902 pTM->tmItalic = pdf->dfItalic;
904 pTM->tmWeight = pdf->dfWeight;
905 if( pfo->fo_flags & FO_SYNTH_BOLD )
907 pTM->tmOverhang++;
908 pTM->tmWeight += 100;
911 *(INT32*)&pTM->tmFirstChar = *(INT32*)&pdf->dfFirstChar;
913 pTM->tmCharSet = pdf->dfCharSet;
914 pTM->tmPitchAndFamily = pdf->dfPitchAndFamily;
916 pTM->tmDigitizedAspectX = pdf->dfHorizRes;
917 pTM->tmDigitizedAspectY = pdf->dfVertRes;
920 /***********************************************************************
921 * XFONT_GetFontMetric
923 * Retrieve font metric info (enumeration).
925 static UINT32 XFONT_GetFontMetric( fontInfo* pfi, LPENUMLOGFONTEX16 pLF,
926 LPNEWTEXTMETRIC16 pTM )
928 memset( pLF, 0, sizeof(*pLF) );
929 memset( pTM, 0, sizeof(*pTM) );
931 #define plf ((LPLOGFONT16)pLF)
932 plf->lfHeight = pTM->tmHeight = pfi->df.dfPixHeight;
933 plf->lfWidth = pTM->tmAveCharWidth = pfi->df.dfAvgWidth;
934 plf->lfWeight = pTM->tmWeight = pfi->df.dfWeight;
935 plf->lfItalic = pTM->tmItalic = pfi->df.dfItalic;
936 plf->lfUnderline = pTM->tmUnderlined = pfi->df.dfUnderline;
937 plf->lfStrikeOut = pTM->tmStruckOut = pfi->df.dfStrikeOut;
938 plf->lfCharSet = pTM->tmCharSet = pfi->df.dfCharSet;
940 /* convert pitch values */
942 pTM->tmPitchAndFamily = pfi->df.dfPitchAndFamily;
943 plf->lfPitchAndFamily = (pfi->df.dfPitchAndFamily & 0xF1) + 1;
945 lstrcpyn32A( plf->lfFaceName, pfi->df.dfFace, LF_FACESIZE );
946 #undef plf
948 pTM->tmAscent = pfi->df.dfAscent;
949 pTM->tmDescent = pTM->tmHeight - pTM->tmAscent;
950 pTM->tmInternalLeading = pfi->df.dfInternalLeading;
951 pTM->tmMaxCharWidth = pfi->df.dfMaxWidth;
952 pTM->tmDigitizedAspectX = pfi->df.dfHorizRes;
953 pTM->tmDigitizedAspectY = pfi->df.dfVertRes;
955 *(INT32*)&pTM->tmFirstChar = *(INT32*)&pfi->df.dfFirstChar;
957 /* return font type */
959 return pfi->df.dfType;
963 /***********************************************************************
964 * XFONT_FixupFlags
966 * dfPitchAndFamily flags for some common typefaces.
968 static BYTE XFONT_FixupFlags( LPCSTR lfFaceName )
970 switch( lfFaceName[0] )
972 case 'h':
973 case 'H': if(!strcasecmp(lfFaceName, "Helvetica") )
974 return FF_SWISS;
975 break;
976 case 'c':
977 case 'C': if(!strcasecmp(lfFaceName, "Courier") ||
978 !strcasecmp(lfFaceName, "Charter") )
979 return FF_ROMAN;
980 break;
981 case 'p':
982 case 'P': if( !strcasecmp(lfFaceName,"Palatino") )
983 return FF_ROMAN;
984 break;
985 case 't':
986 case 'T': if(!strncasecmp(lfFaceName, "Times", 5) )
987 return FF_ROMAN;
988 break;
989 case 'u':
990 case 'U': if(!strcasecmp(lfFaceName, "Utopia") )
991 return FF_ROMAN;
992 break;
993 case 'z':
994 case 'Z': if(!strcasecmp(lfFaceName, "Zapf Dingbats") )
995 return FF_DECORATIVE;
997 return 0;
1001 /***********************************************************************
1002 * XFONT_CheckResourceName
1004 static BOOL32 XFONT_CheckResourceName( LPSTR resource, LPCSTR name, INT32 n )
1006 resource = LFD_Advance( resource, 2 );
1007 if( resource )
1008 return (!strncasecmp( resource, name, n ));
1009 return FALSE;
1013 /***********************************************************************
1014 * XFONT_WindowsNames
1016 * Build generic Windows aliases for X font names.
1018 * -misc-fixed- -> "Fixed"
1019 * -sony-fixed- -> "Sony Fixed", etc...
1021 static void XFONT_WindowsNames( char* buffer )
1023 fontResource* fr, *pfr;
1024 char* lpstr, *lpch;
1025 int i, up;
1026 BYTE bFamilyStyle;
1027 const char* relocTable[] = { INIDefaultFixed, INIDefault, NULL };
1029 for( fr = fontList; fr ; fr = fr->next )
1031 if( fr->fr_flags & FR_NAMESET ) continue; /* skip already assigned */
1033 lpstr = LFD_Advance(fr->resource, 2);
1034 i = LFD_Advance( lpstr, 1 ) - lpstr;
1036 for( pfr = fontList; pfr != fr ; pfr = pfr->next )
1037 if( pfr->fr_flags & FR_NAMESET )
1038 if( XFONT_CheckResourceName( pfr->resource, lpstr, i ) )
1039 break;
1041 if( pfr != fr ) /* prepend vendor name */
1042 lpstr = fr->resource + 1;
1044 for( i = 0, up = 1, lpch = fr->lfFaceName; *lpstr && i < 32;
1045 lpch++, lpstr++, i++ )
1047 if( *lpstr == LFDSeparator[1] || *lpstr == ' ' )
1049 *lpch = ' ';
1050 up = 1; continue;
1052 else if( isalpha(*lpstr) && up )
1054 *lpch = toupper(*lpstr);
1055 up = 0; continue;
1057 *lpch = *lpstr;
1059 while (*(lpch - 1) == ' ') *(--lpch) = '\0';
1061 if( (bFamilyStyle = XFONT_FixupFlags( fr->lfFaceName )) )
1063 fontInfo* fi;
1064 for( fi = fr->fi ; fi ; fi = fi->next )
1065 fi->df.dfPitchAndFamily |= bFamilyStyle;
1068 TRACE(font,"typeface \'%s\'\n", fr->lfFaceName);
1070 fr->fr_flags |= FR_NAMESET;
1073 for( up = 0; relocTable[up]; up++ )
1074 if( PROFILE_GetWineIniString( INIFontSection, relocTable[up], "", buffer, 128 ) )
1076 while( *buffer && isspace(*buffer) ) buffer++;
1077 for( fr = NULL, pfr = fontList; pfr; pfr = pfr->next )
1079 i = strlen( pfr->resource );
1080 if( !strncasecmp( pfr->resource, buffer, i) )
1082 if( fr )
1084 fr->next = pfr->next;
1085 pfr->next = fontList;
1086 fontList = pfr;
1088 break;
1090 fr = pfr;
1095 /***********************************************************************
1096 * XFONT_CreateAlias
1098 static fontAlias* XFONT_CreateAlias( LPCSTR lpTypeFace, LPCSTR lpAlias )
1100 int j;
1101 fontAlias* pfa = aliasTable;
1103 while( 1 )
1105 /* check if we already got one */
1106 if( !strcasecmp( pfa->faTypeFace, lpAlias ) )
1108 TRACE(font,"\tredundant alias '%s' -> '%s'\n",
1109 lpAlias, lpTypeFace );
1110 return NULL;
1112 if( pfa->next ) pfa = pfa->next;
1113 else break;
1116 j = lstrlen32A(lpTypeFace) + 1;
1117 pfa->next = HeapAlloc( SystemHeap, 0, sizeof(fontAlias) +
1118 j + lstrlen32A(lpAlias) + 1 );
1119 if((pfa = pfa->next))
1121 pfa->next = NULL;
1122 pfa->faTypeFace = (LPSTR)(pfa + 1);
1123 lstrcpy32A( pfa->faTypeFace, lpTypeFace );
1124 pfa->faAlias = pfa->faTypeFace + j;
1125 lstrcpy32A( pfa->faAlias, lpAlias );
1127 TRACE(font, "\tadded alias '%s' for %s\n", lpAlias, lpTypeFace );
1129 return pfa;
1131 return NULL;
1134 /***********************************************************************
1135 * XFONT_LoadAliases
1137 * Read user-defined aliases from wine.conf. Format is as follows
1139 * Alias# = [Windows font name],[LFD font name], <substitute original name>
1141 * Example:
1142 * Alias0 = Arial, -adobe-helvetica-
1143 * Alias1 = Times New Roman, -bitstream-courier-, 1
1144 * ...
1146 * Note that from 081797 and on we have built-in alias templates that take
1147 * care of the necessary Windows typefaces.
1149 static void XFONT_LoadAliases( char** buffer, int buf_size )
1151 char* lpResource, *lpAlias;
1152 char subsection[32];
1153 int i = 0, j = 0;
1154 BOOL32 bHaveAlias = TRUE, bSubst = FALSE;
1156 if( buf_size < 128 )
1157 *buffer = HeapReAlloc(SystemHeap, 0, *buffer, 256 );
1160 if( j < faTemplateNum )
1162 /* built-in templates first */
1164 lpResource = faTemplate[j].fatResource;
1165 lpAlias = faTemplate[j].fatAlias;
1166 j++;
1168 else
1170 /* then WINE.CONF */
1172 wsprintf32A( subsection, "%s%i", INISubSection, i++ );
1174 if( (bHaveAlias = PROFILE_GetWineIniString( INIFontSection,
1175 subsection, "", *buffer, 128 )) )
1177 lpAlias = *buffer;
1178 while( isspace(*lpAlias) ) lpAlias++;
1179 lpResource = PROFILE_GetStringItem( lpAlias );
1180 bSubst = (PROFILE_GetStringItem( lpResource )) ? TRUE : FALSE;
1184 if( bHaveAlias )
1186 int length;
1188 length = strlen( lpAlias );
1189 if( lpResource && length )
1191 fontResource* fr, *frMatch = NULL;
1193 for (fr = fontList; fr ; fr = fr->next)
1195 if( !strcasecmp( fr->resource, lpResource ) ) frMatch = fr;
1196 if( XFONT_CheckResourceName( fr->resource, lpAlias, length ) )
1198 /* alias is not needed since the real font is present */
1199 frMatch = NULL; break;
1203 if( frMatch )
1205 if( bSubst )
1207 fontAlias *pfa, *prev = NULL;
1209 for(pfa = aliasTable; pfa; pfa = pfa->next)
1211 /* Remove lpAlias from aliasTable - we should free the old entry */
1212 if(!strcmp(lpAlias, pfa->faAlias))
1214 if(prev)
1215 prev->next = pfa->next;
1216 else
1217 aliasTable = pfa->next;
1220 /* Update any references to the substituted font in aliasTable */
1221 if(!strcmp(frMatch->lfFaceName,
1222 pfa->faTypeFace))
1223 pfa->faTypeFace = HEAP_strdupA( SystemHeap, 0,
1224 lpAlias );
1225 prev = pfa;
1228 TRACE(font, "\tsubstituted '%s' with %s\n",
1229 frMatch->lfFaceName, lpAlias );
1231 lstrcpyn32A( frMatch->lfFaceName, lpAlias, LF_FACESIZE );
1232 frMatch->fr_flags |= FR_NAMESET;
1234 else
1236 /* create new entry in the alias table */
1237 XFONT_CreateAlias( frMatch->lfFaceName, lpAlias );
1241 else ERR(font, " malformed font alias '%s'\n", *buffer );
1243 else break;
1244 } while(TRUE);
1247 /***********************************************************************
1248 * XFONT_UserMetricsCache
1250 * Returns expanded name for the ~/.wine/.cachedmetrics file.
1252 static char* XFONT_UserMetricsCache( char* buffer, int* buf_size )
1254 struct passwd* pwd;
1256 pwd = getpwuid(getuid());
1257 if( pwd && pwd->pw_dir )
1259 int i = strlen( pwd->pw_dir ) + strlen( INIWinePrefix ) +
1260 strlen( INIFontMetrics ) + 2;
1261 if( i > *buf_size )
1262 buffer = (char*) HeapReAlloc( SystemHeap, 0, buffer, *buf_size = i );
1263 strcpy( buffer, pwd->pw_dir );
1264 strcat( buffer, INIWinePrefix );
1265 strcat( buffer, INIFontMetrics );
1266 } else buffer[0] = '\0';
1267 return buffer;
1271 /***********************************************************************
1272 * XFONT_ReadCachedMetrics
1274 static BOOL32 XFONT_ReadCachedMetrics( int fd, int res, unsigned x_checksum, int x_count )
1276 if( fd >= 0 )
1278 unsigned u;
1279 int i, j;
1281 /* read checksums */
1282 read( fd, &u, sizeof(unsigned) );
1283 read( fd, &i, sizeof(int) );
1285 if( u == x_checksum && i == x_count )
1287 off_t length, offset = 3 * sizeof(int);
1289 /* read total size */
1290 read( fd, &i, sizeof(int) );
1291 length = lseek( fd, 0, SEEK_END );
1293 if( length == (i + offset) )
1295 lseek( fd, offset, SEEK_SET );
1296 fontList = (fontResource*)HeapAlloc( SystemHeap, 0, i);
1297 if( fontList )
1299 fontResource* pfr = fontList;
1300 fontInfo* pfi = NULL;
1302 TRACE(font,"Reading cached font metrics:\n");
1304 read( fd, fontList, i); /* read all metrics at once */
1305 while( offset < length )
1307 offset += sizeof(fontResource) + sizeof(fontInfo);
1308 pfr->fi = pfi = (fontInfo*)(pfr + 1);
1309 j = 1;
1310 while( TRUE )
1312 if( offset > length ||
1313 (int)(pfi->next) != j++ ) goto fail;
1315 pfi->df.dfFace = pfr->lfFaceName;
1316 pfi->df.dfHorizRes = pfi->df.dfVertRes = res;
1317 pfi->df.dfPoints = (INT16)(((INT32)(pfi->df.dfPixHeight -
1318 pfi->df.dfInternalLeading) * 72 + (res >> 1)) / res );
1319 pfi->next = pfi + 1;
1321 if( j > pfr->count ) break;
1323 pfi = pfi->next;
1324 offset += sizeof(fontInfo);
1326 pfi->next = NULL;
1327 if( pfr->next )
1329 pfr->next = (fontResource*)(pfi + 1);
1330 pfr = pfr->next;
1332 else break;
1334 if( pfr->next == NULL &&
1335 *(int*)(pfi + 1) == X_FMC_MAGIC )
1337 /* read LFD stubs */
1338 char* lpch = (char*)((int*)(pfi + 1) + 1);
1339 offset += sizeof(int);
1340 for( pfr = fontList; pfr; pfr = pfr->next )
1342 TRACE(font,"\t%s, %i instances\n", lpch, pfr->count );
1343 pfr->resource = lpch;
1344 while( TRUE )
1346 if( ++offset > length ) goto fail;
1347 if( !*lpch++ ) break;
1350 close( fd );
1351 return TRUE;
1356 fail:
1357 if( fontList ) HeapFree( SystemHeap, 0, fontList );
1358 fontList = NULL;
1359 close( fd );
1361 return FALSE;
1364 /***********************************************************************
1365 * XFONT_WriteCachedMetrics
1367 static BOOL32 XFONT_WriteCachedMetrics( int fd, unsigned x_checksum, int x_count, int n_ff )
1369 fontResource* pfr;
1370 fontInfo* pfi;
1372 if( fd >= 0 )
1374 int i, j, k;
1376 /* font metrics file:
1378 * +0000 x_checksum
1379 * +0004 x_count
1380 * +0008 total size to load
1381 * +000C prepackaged font metrics
1382 * ...
1383 * +...x X_FMC_MAGIC
1384 * +...x + 4 LFD stubs
1387 write( fd, &x_checksum, sizeof(unsigned) );
1388 write( fd, &x_count, sizeof(int) );
1390 for( j = i = 0, pfr = fontList; pfr; pfr = pfr->next )
1392 i += strlen( pfr->resource ) + 1;
1393 j += pfr->count;
1395 i += n_ff * sizeof(fontResource) + j * sizeof(fontInfo) + sizeof(int);
1396 write( fd, &i, sizeof(int) );
1398 TRACE(font,"Writing font cache:\n");
1400 for( pfr = fontList; pfr; pfr = pfr->next )
1402 fontInfo fi;
1404 TRACE(font,"\t%s, %i instances\n", pfr->resource, pfr->count );
1406 i = write( fd, pfr, sizeof(fontResource) );
1407 if( i == sizeof(fontResource) )
1409 for( k = 1, pfi = pfr->fi; pfi; pfi = pfi->next )
1411 memcpy( &fi, pfi, sizeof(fi) );
1413 fi.df.dfFace = NULL;
1414 fi.next = (fontInfo*)k; /* loader checks this */
1416 j = write( fd, &fi, sizeof(fi) );
1417 k++;
1419 if( j == sizeof(fontInfo) ) continue;
1421 break;
1423 if( i == sizeof(fontResource) && j == sizeof(fontInfo) )
1425 i = j = X_FMC_MAGIC;
1426 write( fd, &i, sizeof(int) );
1427 for( pfr = fontList; pfr && i == j; pfr = pfr->next )
1429 i = strlen( pfr->resource ) + 1;
1430 j = write( fd, pfr->resource, i );
1433 close( fd );
1434 return ( i == j );
1436 return TRUE;
1439 /***********************************************************************
1440 * XFONT_CheckIniSection
1442 * Examines wine.conf for old/invalid font entries and recommend changes to
1443 * the user.
1445 * Revision history
1446 * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
1447 * Original implementation.
1449 static void XFONT_CheckIniCallback(char const *, char const *, void *);
1451 static char const *fontmsgprologue =
1452 "Wine warning:\n"
1453 " The following entries in the [fonts] section of the wine.conf file are\n"
1454 " obsolete or invalid:\n";
1456 static char const *fontmsgepilogue =
1457 " These entries should be eliminated or updated.\n"
1458 " See the documentation/fonts file for more information.\n";
1460 static int XFONT_CheckIniSection()
1462 int found = 0;
1464 PROFILE_EnumerateWineIniSection("Fonts", &XFONT_CheckIniCallback,
1465 (void *)&found);
1466 if(found)
1467 MSG(fontmsgepilogue);
1469 return 1;
1472 static void XFONT_CheckIniCallback(
1473 char const *key,
1474 char const *value,
1475 void *found)
1477 /* Ignore any keys that start with potential comment characters "'", '#',
1478 or ';'. */
1479 if(key[0] == '\'' || key[0] == '#' || key[0] == ';' || key[0] == '\0')
1480 return;
1482 /* Make sure this is a valid key */
1483 if((strncasecmp(key, INISubSection, 5) == 0) ||
1484 (strcasecmp( key, INIDefault) == 0) ||
1485 (strcasecmp( key, INIDefaultFixed) == 0) ||
1486 (strcasecmp( key, INIGlobalMetrics) == 0) ||
1487 (strcasecmp( key, INIResolution) == 0) )
1489 /* Valid key; make sure the value doesn't contain a wildcard */
1490 if(strchr(value, '*')) {
1491 if(*(int *)found == 0) {
1492 MSG(fontmsgprologue);
1493 ++*(int *)found;
1496 MSG(" %s=%s [no wildcards allowed]\n", key, value);
1499 else {
1500 /* Not a valid key */
1501 if(*(int *)found == 0) {
1502 MSG(fontmsgprologue);
1503 ++*(int *)found;
1506 MSG(" %s=%s [obsolete]\n", key, value);
1509 return;
1512 /***********************************************************************
1513 * XFONT_GetPointResolution()
1515 * Here we initialize DefResolution which is used in the
1516 * XFONT_Match() penalty function. We also load the point
1517 * resolution value (higher values result in larger fonts).
1519 static int XFONT_GetPointResolution( DeviceCaps* pDevCaps )
1521 int i, j, point_resolution, num = 3;
1522 int allowed_xfont_resolutions[3] = { 72, 75, 100 };
1523 int best = 0, best_diff = 65536;
1525 DefResolution = point_resolution = PROFILE_GetWineIniInt( INIFontSection, INIResolution, 0 );
1526 if( !DefResolution ) DefResolution = point_resolution = pDevCaps->logPixelsY;
1527 else pDevCaps->logPixelsX = pDevCaps->logPixelsY = DefResolution;
1529 for( i = best = 0; i < num; i++ )
1531 j = abs( DefResolution - allowed_xfont_resolutions[i] );
1532 if( j < best_diff )
1534 best = i;
1535 best_diff = j;
1538 DefResolution = allowed_xfont_resolutions[best];
1539 return point_resolution;
1542 /***********************************************************************
1543 * X11DRV_FONT_Init
1545 * Initialize font resource list and allocate font cache.
1547 BOOL32 X11DRV_FONT_Init( DeviceCaps* pDevCaps )
1549 XFontStruct* x_fs;
1550 fontResource* fr, *pfr;
1551 fontInfo* fi, *pfi;
1552 unsigned x_checksum;
1553 int i, j, res, x_count, fd = -1, buf_size = 0;
1554 char* lpstr, *lpch, *lpmetrics, *buffer;
1555 char** x_pattern;
1557 XFONT_CheckIniSection();
1559 res = XFONT_GetPointResolution( pDevCaps );
1561 x_pattern = TSXListFonts(display, "*", MAX_FONT_FAMILIES * 16, &x_count );
1563 TRACE(font,"Font Mapper: initializing %i fonts [LPY=%i, XDR=%i, DR=%i]\n",
1564 x_count, pDevCaps->logPixelsY, DefResolution, res);
1565 for( i = x_checksum = 0; i < x_count; i++ )
1567 #if 0
1568 printf("%i\t: %s\n", i, x_pattern[i] );
1569 #endif
1571 j = strlen( x_pattern[i] );
1572 if( j ) x_checksum ^= __genericCheckSum( x_pattern[i], j );
1574 x_checksum |= X_PFONT_MAGIC;
1576 buf_size = 128;
1577 buffer = HeapAlloc( SystemHeap, 0, buf_size );
1578 lpmetrics = NULL;
1580 /* deal with systemwide font metrics cache */
1582 if( PROFILE_GetWineIniString( INIFontSection, INIGlobalMetrics, "", buffer, 128 ) )
1583 fd = open( buffer, O_RDONLY );
1585 if( XFONT_ReadCachedMetrics(fd, res, x_checksum, x_count) == FALSE )
1587 /* try per-user */
1588 buffer = XFONT_UserMetricsCache( buffer, &buf_size );
1589 if( buffer[0] )
1591 fd = open( buffer, O_RDONLY );
1592 if( XFONT_ReadCachedMetrics(fd, res, x_checksum, x_count) == FALSE )
1593 lpmetrics = HEAP_strdupA( SystemHeap, 0, buffer ); /* update later on */
1597 fi = NULL;
1598 if( fontList == NULL ) /* build metrics from scratch */
1600 int n_ff;
1601 char* typeface;
1603 for( i = n_ff = 0; i < x_count; i++ )
1605 typeface = lpch = x_pattern[i];
1607 lpch = LFD_Advance(typeface, 3); /* extra '-' in the beginning */
1608 if( !*lpch ) continue;
1610 lpstr = lpch;
1611 j = lpch - typeface; /* resource name length */
1613 /* find a family to insert into */
1615 for( pfr = NULL, fr = fontList; fr; fr = fr->next )
1617 if( !strncasecmp(fr->resource, typeface, j) &&
1618 strlen(fr->resource) == j ) break;
1619 pfr = fr;
1622 if( !fi ) fi = (fontInfo*) HeapAlloc(SystemHeap, 0, sizeof(fontInfo));
1624 if( !fr ) /* add new family */
1626 if( n_ff >= MAX_FONT_FAMILIES ) break;
1627 if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1629 n_ff++;
1630 fr = (fontResource*) HeapAlloc(SystemHeap, 0, sizeof(fontResource));
1631 memset(fr, 0, sizeof(fontResource));
1632 fr->resource = (char*) HeapAlloc(SystemHeap, 0, j + 1 );
1633 lstrcpyn32A( fr->resource, typeface, j + 1 );
1635 TRACE(font," family: %s\n", fr->resource );
1637 if( pfr ) pfr->next = fr;
1638 else fontList = fr;
1640 else if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1642 /* check if we already have something better than "fi" */
1644 for( pfi = fr->fi, j = 0; pfi && j <= 0; pfi = pfi->next )
1645 if( (j = XFONT_IsSubset( pfi, fi )) < 0 )
1646 pfi->fi_flags |= FI_SUBSET; /* superseded by "fi" */
1647 if( j > 0 ) continue;
1649 /* add new font instance "fi" to the "fr" font resource */
1651 if( fi->fi_flags & FI_SCALABLE )
1653 /* set scalable font height to 24 to get an origin for extrapolation */
1655 j = strlen(typeface); j += 0x10;
1656 if( j > buf_size )
1657 buffer = (char*)HeapReAlloc( SystemHeap, 0, buffer, buf_size = j );
1659 lpch = LFD_Advance(typeface, 7);
1660 memcpy( buffer, typeface, (j = lpch - typeface) );
1661 lpch = LFD_Advance(lpch, 4);
1662 sprintf( buffer + j, "%d-%d-%d-*-%c-*-", fi->lfd_height,
1663 fi->lfd_decipoints, fi->lfd_resolution,
1664 (*lpch == '-')?'*':*lpch );
1665 lpch = LFD_Advance(lpch, 2);
1666 strcat( lpstr = buffer, lpch);
1668 else lpstr = typeface;
1670 if( (x_fs = TSXLoadQueryFont(display, lpstr)) )
1672 fi->df.dfHorizRes = fi->df.dfVertRes = res;
1674 XFONT_SetFontMetric( fi, fr, x_fs );
1675 TSXFreeFont( display, x_fs );
1677 TRACE(font,"\t[% 2ipt] '%s'\n", fi->df.dfPoints, typeface );
1679 XFONT_CheckFIList( fr, fi, REMOVE_SUBSETS );
1680 fi = NULL; /* preventing reuse */
1682 else
1684 ERR(font, "failed to load %s\n", lpstr );
1686 XFONT_CheckFIList( fr, fi, UNMARK_SUBSETS );
1690 if( lpmetrics ) /* update cached metrics */
1692 fd = open( lpmetrics, O_CREAT | O_TRUNC | O_RDWR, 0644 ); /* -rw-r--r-- */
1693 if( XFONT_WriteCachedMetrics( fd, x_checksum, x_count, n_ff ) == FALSE )
1694 if( fd ) remove( lpmetrics ); /* couldn't write entire file */
1695 HeapFree( SystemHeap, 0, lpmetrics );
1699 if( fi ) HeapFree(SystemHeap, 0, fi);
1700 TSXFreeFontNames(x_pattern);
1702 /* check if we're dealing with X11 R6 server */
1704 strcpy(buffer, "-*-*-*-*-normal-*-[12 0 0 12]-*-72-*-*-*-iso8859-1");
1705 if( (x_fs = TSXLoadQueryFont(display, buffer)) )
1707 XTextCaps |= TC_SF_X_YINDEP;
1708 TSXFreeFont(display, x_fs);
1711 XFONT_WindowsNames( buffer );
1712 XFONT_LoadAliases( &buffer, buf_size );
1713 HeapFree(SystemHeap, 0, buffer);
1716 /* fontList initialization is over, allocate X font cache */
1718 fontCache = (fontObject*) HeapAlloc(SystemHeap, 0, fontCacheSize * sizeof(fontObject));
1719 XFONT_GrowFreeList(0, fontCacheSize - 1);
1721 TRACE(font,"done!\n");
1723 /* update text caps parameter */
1725 pDevCaps->textCaps = XTextCaps;
1727 RAW_ASCENT = TSXInternAtom(display, "RAW_ASCENT", TRUE);
1728 RAW_DESCENT = TSXInternAtom(display, "RAW_DESCENT", TRUE);
1730 return TRUE;
1734 /***********************************************************************
1735 * X Font Matching
1737 * Compare two fonts (only parameters set by the XFONT_InitFontInfo()).
1739 static INT32 XFONT_IsSubset(fontInfo* match, fontInfo* fi)
1741 INT32 m;
1743 /* 0 - keep both, 1 - keep match, -1 - keep fi */
1745 m = (BYTE*)&fi->df.dfPixWidth - (BYTE*)&fi->df.dfItalic;
1746 if( memcmp(&match->df.dfItalic, &fi->df.dfItalic, m )) return 0;
1748 if( (!((fi->fi_flags & FI_SCALABLE) + (match->fi_flags & FI_SCALABLE))
1749 && fi->lfd_height != match->lfd_height) ||
1750 (!((fi->fi_flags & FI_POLYWEIGHT) + (match->fi_flags & FI_POLYWEIGHT))
1751 && fi->df.dfWeight != match->df.dfWeight) ) return 0;
1753 m = (int)(match->fi_flags & (FI_POLYWEIGHT | FI_SCALABLE)) -
1754 (int)(fi->fi_flags & (FI_SCALABLE | FI_POLYWEIGHT));
1756 if( m == (FI_POLYWEIGHT - FI_SCALABLE) ||
1757 m == (FI_SCALABLE - FI_POLYWEIGHT) ) return 0; /* keep both */
1758 else if( m >= 0 ) return 1; /* 'match' is better */
1760 return -1; /* 'fi' is better */
1763 /***********************************************************************
1764 * XFONT_Match
1766 * Compute the matching score between the logical font and the device font.
1768 * contributions from highest to lowest:
1769 * charset
1770 * fixed pitch
1771 * height
1772 * family flags (only when the facename is not present)
1773 * width
1774 * weight, italics, underlines, strikeouts
1776 * NOTE: you can experiment with different penalty weights to see what happens.
1777 * http://premium.microsoft.com/msdn/library/techart/f365/f36b/f37b/d38b/sa8bf.htm
1779 static UINT32 XFONT_Match( fontMatch* pfm )
1781 fontInfo* pfi = pfm->pfi; /* device font to match */
1782 LPLOGFONT16 plf = pfm->plf; /* wanted logical font */
1783 UINT32 penalty = 0;
1784 BOOL32 bR6 = pfm->flags & FO_MATCH_XYINDEP; /* from TextCaps */
1785 BOOL32 bScale = pfi->fi_flags & FI_SCALABLE;
1786 INT32 d, h;
1788 TRACE(font,"\t[ %-2ipt h=%-3i w=%-3i %s%s]\n", pfi->df.dfPoints,
1789 pfi->df.dfPixHeight, pfi->df.dfAvgWidth,
1790 (pfi->df.dfWeight > 400) ? "Bold " : "Normal ",
1791 (pfi->df.dfItalic) ? "Italic" : "" );
1793 pfm->flags = 0;
1795 if( plf->lfCharSet == DEFAULT_CHARSET )
1797 if( (pfi->df.dfCharSet!= ANSI_CHARSET) && (pfi->df.dfCharSet!=DEFAULT_CHARSET) )
1798 penalty += 0x200;
1800 else if (plf->lfCharSet != pfi->df.dfCharSet) penalty += 0x200;
1802 /* FIXME: Hack to demote symbols and nil fonts. Should take into
1803 account if a program ever actually asked for this type of
1804 font */
1805 if ( (strcmp(pfm->pfr->lfFaceName,"Symbol")==0) || (strcmp(pfm->pfr->lfFaceName,"Nil")==0) )
1806 penalty += 0x200; /* very stiff penality */
1808 /* TMPF_FIXED_PITCH means exactly the opposite */
1810 if( plf->lfPitchAndFamily & FIXED_PITCH )
1812 if( pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH ) penalty += 0x100;
1814 else if( !(pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH) ) penalty += 0x2;
1816 if( plf->lfHeight > 0 )
1817 d = (h = pfi->df.dfPixHeight) - plf->lfHeight;
1818 else if( plf->lfHeight < -1 )
1819 d = (h = pfi->df.dfPoints) + plf->lfHeight;
1820 else d = h = 0;
1822 if( d && plf->lfHeight )
1824 UINT16 height = ( plf->lfHeight > 0 ) ? plf->lfHeight
1825 : ((-plf->lfHeight * pfi->df.dfPixHeight) / h);
1826 if( bScale ) pfm->height = height;
1827 else if( (plf->lfQuality != PROOF_QUALITY) && bR6 )
1829 if( d > 0 ) /* do not shrink raster fonts */
1831 pfm->height = pfi->df.dfPixHeight;
1832 penalty += (pfi->df.dfPixHeight - height) * 0x4;
1834 else /* expand only in integer multiples */
1836 pfm->height = height - height%pfi->df.dfPixHeight;
1837 penalty += (height - pfm->height + 1) * height / pfi->df.dfPixHeight;
1840 else /* can't be scaled at all */
1842 if( plf->lfQuality != PROOF_QUALITY) pfm->flags |= FO_SYNTH_HEIGHT;
1843 pfm->height = pfi->df.dfPixHeight;
1844 penalty += (d > 0)? d * 0x8 : -d * 0x10;
1846 } else pfm->height = pfi->df.dfPixHeight;
1848 if((pfm->flags & FO_MATCH_PAF) &&
1849 (plf->lfPitchAndFamily & FF_FAMILY) != (pfi->df.dfPitchAndFamily & FF_FAMILY) )
1850 penalty += 0x10;
1852 if( plf->lfWidth )
1854 if( bR6 && bScale ) h = 0;
1855 else
1857 /* FIXME: not complete */
1859 pfm->flags |= FO_SYNTH_WIDTH;
1860 h = abs(plf->lfWidth - (pfm->height * pfi->df.dfAvgWidth)/pfi->df.dfPixHeight);
1862 penalty += h * ( d ) ? 0x2 : 0x1 ;
1864 else if( !(pfi->fi_flags & FI_NORMAL) ) penalty++;
1866 if( plf->lfWeight != FW_DONTCARE )
1868 penalty += abs(plf->lfWeight - pfi->df.dfWeight) / 40;
1869 if( plf->lfWeight > pfi->df.dfWeight ) pfm->flags |= FO_SYNTH_BOLD;
1870 } else if( pfi->df.dfWeight >= FW_BOLD ) penalty++; /* choose normal by default */
1872 if( plf->lfItalic != pfi->df.dfItalic )
1874 penalty += 0x4;
1875 pfm->flags |= FO_SYNTH_ITALIC;
1878 if( plf->lfUnderline ) pfm->flags |= FO_SYNTH_UNDERLINE;
1879 if( plf->lfStrikeOut ) pfm->flags |= FO_SYNTH_STRIKEOUT;
1881 if( penalty && pfi->lfd_resolution != DefResolution )
1882 penalty++;
1884 TRACE(font," returning %i\n", penalty );
1886 return penalty;
1889 /***********************************************************************
1890 * XFONT_MatchFIList
1892 * Scan a particular font resource for the best match.
1894 static UINT32 XFONT_MatchFIList( fontMatch* pfm )
1896 BOOL32 skipRaster = (pfm->flags & FO_MATCH_NORASTER);
1897 UINT32 current_score, score = (UINT32)(-1);
1898 UINT16 origflags = pfm->flags; /* Preserve FO_MATCH_XYINDEP */
1899 fontMatch fm = *pfm;
1901 for( fm.pfi = pfm->pfr->fi; fm.pfi && score; fm.pfi = fm.pfi->next,
1902 fm.flags = origflags )
1904 if( skipRaster && !(fm.pfi->fi_flags & FI_SCALABLE) )
1905 continue;
1907 current_score = XFONT_Match( &fm );
1908 if( score > current_score )
1910 memcpy( pfm, &fm, sizeof(fontMatch) );
1911 score = current_score;
1914 return score;
1917 /***********************************************************************
1918 * XFONT_CheckFIList
1920 * REMOVE_SUBSETS - attach new fi and purge subsets
1921 * UNMARK_SUBSETS - remove subset flags from all fi entries
1923 static void XFONT_CheckFIList( fontResource* fr, fontInfo* fi, int action)
1925 int i = 0;
1926 fontInfo* pfi, *prev;
1928 for( prev = NULL, pfi = fr->fi; pfi; )
1930 if( action == REMOVE_SUBSETS )
1932 if( pfi->fi_flags & FI_SUBSET )
1934 fontInfo* subset = pfi;
1936 i++;
1937 fr->count--;
1938 if( prev ) prev->next = pfi = pfi->next;
1939 else fr->fi = pfi = pfi->next;
1940 HeapFree( SystemHeap, 0, subset );
1941 continue;
1944 else pfi->fi_flags &= ~FI_SUBSET;
1946 prev = pfi;
1947 pfi = pfi->next;
1950 if( action == REMOVE_SUBSETS ) /* also add the superset */
1952 if( fi->fi_flags & FI_SCALABLE )
1954 fi->next = fr->fi;
1955 fr->fi = fi;
1957 else if( prev ) prev->next = fi; else fr->fi = fi;
1958 fr->count++;
1961 if( i ) TRACE(font,"\t purged %i subsets [%i]\n", i , fr->count);
1964 /***********************************************************************
1965 * XFONT_FindFIList
1967 static fontResource* XFONT_FindFIList( fontResource* pfr, const char* pTypeFace )
1969 while( pfr )
1971 if( !strcasecmp( pfr->lfFaceName, pTypeFace ) ) break;
1972 pfr = pfr->next;
1974 return pfr;
1977 /***********************************************************************
1978 * XFONT_MatchDeviceFont
1980 * Scan font resource tree.
1982 static BOOL32 XFONT_MatchDeviceFont( fontResource* start, fontMatch* pfm )
1984 fontMatch fm = *pfm;
1986 pfm->pfi = NULL;
1987 if( fm.plf->lfFaceName[0] )
1989 fontAlias* fa;
1990 LPSTR str = NULL;
1992 for( fa = aliasTable; fa; fa = fa->next )
1993 if( !strcmp( fa->faAlias, fm.plf->lfFaceName ) )
1995 str = fa->faTypeFace;
1996 break;
1998 fm.pfr = XFONT_FindFIList( start, str ? str : fm.plf->lfFaceName );
2001 if( fm.pfr ) /* match family */
2003 TRACE(font, "%s\n", fm.pfr->lfFaceName );
2005 XFONT_MatchFIList( &fm );
2006 *pfm = fm;
2009 if( !pfm->pfi ) /* match all available fonts */
2011 UINT32 current_score, score = (UINT32)(-1);
2013 fm.flags |= FO_MATCH_PAF;
2014 for( start = fontList; start && score; start = start->next )
2016 fm.pfr = start;
2018 TRACE(font, "%s\n", fm.pfr->lfFaceName );
2020 current_score = XFONT_MatchFIList( &fm );
2021 if( current_score < score )
2023 score = current_score;
2024 *pfm = fm;
2028 return TRUE;
2032 /***********************************************************************
2033 * X Font Cache
2035 static void XFONT_GrowFreeList(int start, int end)
2037 /* add all entries from 'start' up to and including 'end' */
2039 memset( fontCache + start, 0, (end - start + 1) * sizeof(fontObject) );
2041 fontCache[end].lru = fontLF;
2042 fontCache[end].count = -1;
2043 fontLF = start;
2044 while( start < end )
2046 fontCache[start].count = -1;
2047 fontCache[start].lru = start + 1;
2048 start++;
2052 static fontObject* XFONT_LookupCachedFont( LPLOGFONT16 plf, UINT16* checksum )
2054 UINT16 cs = __lfCheckSum( plf );
2055 int i = fontMRU, prev = -1;
2057 *checksum = cs;
2058 while( i >= 0 )
2060 if( fontCache[i].lfchecksum == cs &&
2061 !(fontCache[i].fo_flags & FO_REMOVED) )
2063 /* FIXME: something more intelligent here */
2065 if( !memcmp( plf, &fontCache[i].lf,
2066 sizeof(LOGFONT16) - LF_FACESIZE ) &&
2067 !strncasecmp( plf->lfFaceName, fontCache[i].lf.lfFaceName,
2068 LF_FACESIZE ) )
2070 /* remove temporarily from the lru list */
2072 if( prev >= 0 )
2073 fontCache[prev].lru = fontCache[i].lru;
2074 else
2075 fontMRU = (INT16)fontCache[i].lru;
2076 return (fontCache + i);
2079 prev = i;
2080 i = (INT16)fontCache[i].lru;
2082 return NULL;
2085 static fontObject* XFONT_GetCacheEntry()
2087 int i;
2089 if( fontLF == -1 )
2091 int prev_i, prev_j, j;
2093 TRACE(font,"font cache is full\n");
2095 /* lookup the least recently used font */
2097 for( prev_i = prev_j = j = -1, i = fontMRU; i >= 0; i = (INT16)fontCache[i].lru )
2099 if( fontCache[i].count <= 0 &&
2100 !(fontCache[i].fo_flags & FO_SYSTEM) )
2102 prev_j = prev_i;
2103 j = i;
2105 prev_i = i;
2108 if( j >= 0 ) /* unload font */
2110 /* detach from the lru list */
2112 TRACE(font,"\tfreeing entry %i\n", j );
2114 if( prev_j >= 0 )
2115 fontCache[prev_j].lru = fontCache[j].lru;
2116 else fontMRU = (INT16)fontCache[j].lru;
2118 /* FIXME: lpXForm, lpPixmap */
2119 if(fontCache[j].lpX11Trans)
2120 HeapFree( SystemHeap, 0, fontCache[j].lpX11Trans );
2122 TSXFreeFont( display, fontCache[j].fs );
2124 memset( fontCache + j, 0, sizeof(fontObject) );
2125 return (fontCache + j);
2127 else /* expand cache */
2129 fontObject* newCache;
2131 prev_i = fontCacheSize + FONTCACHE;
2133 TRACE(font,"\tgrowing font cache from %i to %i\n", fontCacheSize, prev_i );
2135 if( (newCache = (fontObject*)HeapReAlloc(SystemHeap, 0,
2136 fontCache, prev_i)) )
2138 i = fontCacheSize;
2139 fontCacheSize = prev_i;
2140 fontCache = newCache;
2141 XFONT_GrowFreeList( i, fontCacheSize - 1);
2143 else return NULL;
2147 /* detach from the free list */
2149 i = fontLF;
2150 fontLF = (INT16)fontCache[i].lru;
2151 fontCache[i].count = 0;
2152 return (fontCache + i);
2155 static int XFONT_ReleaseCacheEntry(fontObject* pfo)
2157 UINT32 u = (UINT32)(pfo - fontCache);
2159 if( u < fontCacheSize ) return (--fontCache[u].count);
2160 return -1;
2163 /**********************************************************************
2164 * XFONT_SetX11Trans
2166 static BOOL32 XFONT_SetX11Trans( fontObject *pfo )
2168 char *fontName;
2169 Atom nameAtom;
2170 int i;
2171 char *cp, *start;
2173 TSXGetFontProperty( pfo->fs, XA_FONT, &nameAtom );
2174 fontName = TSXGetAtomName( display, nameAtom );
2175 for(i = 0, cp = fontName; i < 7; i++) {
2176 cp = strchr(cp, '-');
2177 cp++;
2179 if(*cp != '[') {
2180 TSXFree(fontName);
2181 return FALSE;
2183 start = cp;
2184 while((cp = strchr(cp, '~')))
2185 *cp = '-';
2187 #define PX pfo->lpX11Trans
2189 sscanf(start, "[%f%f%f%f]", &PX->a, &PX->b, &PX->c, &PX->d);
2190 TSXFree(fontName);
2192 TSXGetFontProperty( pfo->fs, RAW_ASCENT, &PX->RAW_ASCENT );
2193 TSXGetFontProperty( pfo->fs, RAW_DESCENT, &PX->RAW_DESCENT );
2195 PX->pixelsize = hypot(PX->a, PX->b);
2196 PX->ascent = PX->pixelsize / 1000.0 * PX->RAW_ASCENT;
2197 PX->descent = PX->pixelsize / 1000.0 * PX->RAW_DESCENT;
2199 TRACE(font, "[%f %f %f %f] RA = %ld RD = %ld\n", pfo->lpX11Trans->a,
2200 pfo->lpX11Trans->b, pfo->lpX11Trans->c, pfo->lpX11Trans->d,
2201 pfo->lpX11Trans->RAW_ASCENT, pfo->lpX11Trans->RAW_DESCENT);
2203 #undef PX
2204 return TRUE;
2207 /***********************************************************************
2208 * X Device Font Objects
2210 static X_PHYSFONT XFONT_RealizeFont( LPLOGFONT16 plf )
2212 UINT16 checksum;
2213 fontObject* pfo = XFONT_LookupCachedFont( plf, &checksum );
2215 if( !pfo )
2217 fontMatch fm = { NULL, NULL, 0, 0, plf};
2218 INT32 i, index;
2220 if( XTextCaps & TC_SF_X_YINDEP ) fm.flags = FO_MATCH_XYINDEP;
2222 /* allocate new font cache entry */
2224 if( (pfo = XFONT_GetCacheEntry()) )
2226 LPSTR lpLFD = HeapAlloc( GetProcessHeap(), 0, MAX_LFD_LENGTH );
2228 if( lpLFD ) /* initialize entry and load font */
2230 UINT32 uRelaxLevel = 0;
2232 TRACE(font,"(%u) '%s' h=%i weight=%i %s\n",
2233 plf->lfCharSet, plf->lfFaceName, plf->lfHeight,
2234 plf->lfWeight, (plf->lfItalic) ? "Italic" : "" );
2236 if(abs(plf->lfHeight) > MAX_FONT_SIZE) {
2237 ERR(font,
2238 "plf->lfHeight = %d, this is probably not right. Setting to 100\n",
2239 plf->lfHeight);
2240 plf->lfHeight = 100;
2243 XFONT_MatchDeviceFont( fontList, &fm );
2245 pfo->fr = fm.pfr;
2246 pfo->fi = fm.pfi;
2247 pfo->fo_flags = fm.flags & ~FO_MATCH_MASK;
2249 memcpy( &pfo->lf, plf, sizeof(LOGFONT16) );
2250 pfo->lfchecksum = checksum;
2254 LFD_ComposeLFD( pfo, fm.height, lpLFD, uRelaxLevel++ );
2255 if( (pfo->fs = TSXLoadQueryFont( display, lpLFD )) ) break;
2256 } while( uRelaxLevel );
2259 if(pfo->lf.lfEscapement != 0) {
2260 pfo->lpX11Trans = HeapAlloc(SystemHeap, 0,
2261 sizeof(XFONTTRANS));
2262 if(!XFONT_SetX11Trans( pfo )) {
2263 HeapFree(SystemHeap, 0, pfo->lpX11Trans);
2264 pfo->lpX11Trans = NULL;
2268 if( XFONT_GetLeading( &pfo->fi->df, pfo->fs, &i, NULL,
2269 pfo->lpX11Trans ) )
2271 if(!pfo->lpX11Trans)
2272 pfo->foAvgCharWidth =
2273 (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].width;
2274 else
2275 pfo->foAvgCharWidth =
2276 (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].attributes
2277 * pfo->lpX11Trans->pixelsize / 1000.0;
2278 else
2279 pfo->foAvgCharWidth = (INT16)XFONT_GetAvgCharWidth(
2280 &pfo->fi->df, pfo->fs, pfo->lpX11Trans );
2281 pfo->foMaxCharWidth = (INT16)XFONT_GetMaxCharWidth(pfo);
2282 pfo->foInternalLeading = (INT16)i;
2284 /* FIXME: If we've got a soft font or
2285 * there are FO_SYNTH_... flags for the
2286 * non PROOF_QUALITY request, the engine
2287 * should rasterize characters into mono
2288 * pixmaps and store them in the pfo->lpPixmap
2289 * array (pfo->fs should be updated as well).
2290 * X11DRV_ExtTextOut() must be heavily modified
2291 * to support pixmap blitting and FO_SYNTH_...
2292 * styles.
2295 pfo->lpXForm = NULL;
2296 pfo->lpPixmap = NULL;
2298 HeapFree( GetProcessHeap(), 0, lpLFD );
2300 else /* attach back to the free list */
2302 pfo->count = -1;
2303 pfo->lru = fontLF;
2304 fontLF = (pfo - fontCache);
2305 pfo = NULL;
2309 if( !pfo ) /* couldn't get a new entry, get one of the cached fonts */
2311 UINT32 current_score, score = (UINT32)(-1);
2313 i = index = fontMRU;
2314 fm.flags |= FO_MATCH_PAF;
2317 pfo = fontCache + i;
2318 fm.pfr = pfo->fr; fm.pfi = pfo->fi;
2320 current_score = XFONT_Match( &fm );
2321 if( current_score < score ) index = i;
2323 i = pfo->lru;
2324 } while( i >= 0 );
2325 pfo = fontCache + index;
2326 pfo->count++;
2327 return (X_PHYSFONT)(X_PFONT_MAGIC | index);
2331 /* attach at the head of the lru list */
2333 pfo->count++;
2334 pfo->lru = fontMRU;
2335 fontMRU = (pfo - fontCache);
2337 TRACE(font,"physfont %i\n", fontMRU);
2339 return (X_PHYSFONT)(X_PFONT_MAGIC | fontMRU);
2342 /***********************************************************************
2343 * XFONT_GetFontObject
2345 fontObject* XFONT_GetFontObject( X_PHYSFONT pFont )
2347 if( CHECK_PFONT(pFont) ) return __PFONT(pFont);
2348 return NULL;
2351 /***********************************************************************
2352 * XFONT_GetFontStruct
2354 XFontStruct* XFONT_GetFontStruct( X_PHYSFONT pFont )
2356 if( CHECK_PFONT(pFont) ) return __PFONT(pFont)->fs;
2357 return NULL;
2360 /***********************************************************************
2361 * XFONT_GetFontInfo
2363 LPIFONTINFO16 XFONT_GetFontInfo( X_PHYSFONT pFont )
2365 if( CHECK_PFONT(pFont) ) return &(__PFONT(pFont)->fi->df);
2366 return NULL;
2371 /* X11DRV Interface ****************************************************
2373 * Exposed via the dc->funcs dispatch table. *
2375 ***********************************************************************/
2376 /***********************************************************************
2377 * X11DRV_FONT_SelectObject
2379 HFONT32 X11DRV_FONT_SelectObject( DC* dc, HFONT32 hfont, FONTOBJ* font )
2381 HFONT32 hPrevFont = 0;
2382 LOGFONT16 lf;
2383 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2385 if( CHECK_PFONT(physDev->font) )
2386 XFONT_ReleaseCacheEntry( __PFONT(physDev->font) );
2388 /* FIXME: do we need to pass anything back from here? */
2389 memcpy(&lf,&font->logfont,sizeof(lf));
2390 lf.lfWidth = font->logfont.lfWidth * dc->vportExtX/dc->wndExtX;
2391 lf.lfHeight = font->logfont.lfHeight* dc->vportExtY/dc->wndExtY;
2393 physDev->font = XFONT_RealizeFont( &lf );
2394 hPrevFont = dc->w.hFont;
2395 dc->w.hFont = hfont;
2397 return hPrevFont;
2401 /***********************************************************************
2403 * X11DRV_EnumDeviceFonts
2405 BOOL32 X11DRV_EnumDeviceFonts( DC* dc, LPLOGFONT16 plf,
2406 DEVICEFONTENUMPROC proc, LPARAM lp )
2408 ENUMLOGFONTEX16 lf;
2409 NEWTEXTMETRIC16 tm;
2410 fontResource* pfr = fontList;
2411 BOOL32 b, bRet = 0;
2413 if( plf->lfFaceName[0] )
2415 pfr = XFONT_FindFIList( pfr, plf->lfFaceName );
2416 if( pfr )
2418 fontInfo* pfi;
2419 for( pfi = pfr->fi; pfi; pfi = pfi->next )
2420 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
2421 XFONT_GetFontMetric( pfi, &lf, &tm ), lp )) )
2422 bRet = b;
2423 else break;
2426 else
2427 for( ; pfr ; pfr = pfr->next )
2428 if(pfr->fi)
2430 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
2431 XFONT_GetFontMetric( pfr->fi, &lf, &tm ), lp )) )
2432 bRet = b;
2433 else break;
2436 return bRet;
2440 /***********************************************************************
2441 * X11DRV_GetTextExtentPoint
2443 BOOL32 X11DRV_GetTextExtentPoint( DC *dc, LPCSTR str, INT32 count,
2444 LPSIZE32 size )
2446 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2447 fontObject* pfo = XFONT_GetFontObject( physDev->font );
2448 if( pfo ) {
2449 if( !pfo->lpX11Trans ) {
2450 int dir, ascent, descent;
2451 XCharStruct info;
2453 TSXTextExtents( pfo->fs, str, count, &dir, &ascent, &descent, &info );
2454 size->cx = abs((info.width + dc->w.breakRem + count *
2455 dc->w.charExtra) * dc->wndExtX / dc->vportExtX);
2456 size->cy = abs((pfo->fs->ascent + pfo->fs->descent) *
2457 dc->wndExtY / dc->vportExtY);
2458 } else {
2460 INT32 i;
2461 float x = 0.0, y = 0.0;
2462 for(i = 0; i < count; i++) {
2463 x += pfo->fs->per_char ?
2464 pfo->fs->per_char[str[i] - pfo->fs->min_char_or_byte2].attributes :
2465 pfo->fs->min_bounds.attributes;
2467 y = pfo->lpX11Trans->RAW_ASCENT + pfo->lpX11Trans->RAW_DESCENT;
2468 TRACE(font, "x = %f y = %f\n", x, y);
2469 x *= pfo->lpX11Trans->pixelsize / 1000.0;
2470 y *= pfo->lpX11Trans->pixelsize / 1000.0;
2471 size->cx = fabsf((x + dc->w.breakRem + count * dc->w.charExtra) *
2472 dc->wndExtX / dc->vportExtX);
2473 size->cy = fabsf(y * dc->wndExtY / dc->vportExtY);
2475 return TRUE;
2477 return FALSE;
2481 /***********************************************************************
2482 * X11DRV_GetTextMetrics
2484 BOOL32 X11DRV_GetTextMetrics(DC *dc, TEXTMETRIC32A *metrics)
2486 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2488 if( CHECK_PFONT(physDev->font) )
2490 fontObject* pfo = __PFONT(physDev->font);
2491 XFONT_GetTextMetric( pfo, metrics );
2493 return TRUE;
2495 return FALSE;
2499 /***********************************************************************
2500 * X11DRV_GetCharWidth
2502 BOOL32 X11DRV_GetCharWidth( DC *dc, UINT32 firstChar, UINT32 lastChar,
2503 LPINT32 buffer )
2505 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2506 fontObject* pfo = XFONT_GetFontObject( physDev->font );
2508 if( pfo )
2510 int i;
2512 if (pfo->fs->per_char == NULL)
2513 for (i = firstChar; i <= lastChar; i++)
2514 if(pfo->lpX11Trans)
2515 *buffer++ = pfo->fs->min_bounds.attributes *
2516 pfo->lpX11Trans->pixelsize / 1000.0;
2517 else
2518 *buffer++ = pfo->fs->min_bounds.width;
2519 else
2521 XCharStruct *cs, *def;
2522 static XCharStruct __null_char = { 0, 0, 0, 0, 0, 0 };
2524 CI_GET_CHAR_INFO(pfo->fs, pfo->fs->default_char, &__null_char,
2525 def);
2527 for (i = firstChar; i <= lastChar; i++)
2529 if (i >= pfo->fs->min_char_or_byte2 &&
2530 i <= pfo->fs->max_char_or_byte2)
2532 cs = &pfo->fs->per_char[(i - pfo->fs->min_char_or_byte2)];
2533 if (CI_NONEXISTCHAR(cs)) cs = def;
2534 } else cs = def;
2535 if(pfo->lpX11Trans)
2536 *buffer++ = MAX(cs->attributes, 0) *
2537 pfo->lpX11Trans->pixelsize / 1000.0;
2538 else
2539 *buffer++ = MAX(cs->width, 0 );
2543 return TRUE;
2545 return FALSE;
2548 /***********************************************************************
2550 * Font Resource API *
2552 ***********************************************************************/
2553 /***********************************************************************
2554 * AddFontResource16 (GDI.119)
2556 * Can be either .FON, or .FNT, or .TTF, or .FOT font file.
2558 * FIXME: Load header and find the best-matching font in the fontList;
2559 * fixup dfPoints if all metrics are identical, otherwise create
2560 * new fontAlias. When soft font support is ready this will
2561 * simply create a new fontResource ('filename' will go into
2562 * the pfr->resource field) with FR_SOFTFONT/FR_SOFTRESOURCE
2563 * flag set.
2565 INT16 WINAPI AddFontResource16( LPCSTR filename )
2567 return AddFontResource32A( filename );
2571 /***********************************************************************
2572 * AddFontResource32A (GDI32.2)
2574 INT32 WINAPI AddFontResource32A( LPCSTR str )
2576 FIXME(font, "(%s): stub\n", debugres_a(str));
2577 return 1;
2581 /***********************************************************************
2582 * AddFontResource32W (GDI32.4)
2584 INT32 WINAPI AddFontResource32W( LPCWSTR str )
2586 FIXME(font, "(%s): stub\n", debugres_w(str) );
2587 return 1;
2590 /***********************************************************************
2591 * RemoveFontResource16 (GDI.136)
2593 BOOL16 WINAPI RemoveFontResource16( SEGPTR str )
2595 FIXME(font, "(%s): stub\n", debugres_a(PTR_SEG_TO_LIN(str)));
2596 return TRUE;
2600 /***********************************************************************
2601 * RemoveFontResource32A (GDI32.284)
2603 BOOL32 WINAPI RemoveFontResource32A( LPCSTR str )
2605 FIXME(font, "(%s): stub\n", debugres_a(str));
2606 return TRUE;
2610 /***********************************************************************
2611 * RemoveFontResource32W (GDI32.286)
2613 BOOL32 WINAPI RemoveFontResource32W( LPCWSTR str )
2615 FIXME(font, "(%s): stub\n", debugres_w(str) );
2616 return TRUE;