Release 970629
[wine/testsucceed.git] / graphics / x11drv / xfont.c
blobf12d89f3fd6cd05e8dccd100e69cd1812ca52056
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 <X11/Xlib.h>
20 #include <X11/Xatom.h>
21 #include "heap.h"
22 #include "options.h"
23 #include "x11font.h"
24 #include "font.h"
25 #include "stddebug.h"
26 #include "debug.h"
28 #define DEBUG_FONT_INIT 1
30 #define X_PFONT_MAGIC (0xFADE0000)
31 #define X_FMC_MAGIC (0x0000CAFE)
33 #define MAX_FONT_FAMILIES 64
34 #define MAX_LFD_LENGTH 128
36 #define REMOVE_SUBSETS 1
37 #define UNMARK_SUBSETS 0
39 #define DEF_SCALABLE_HEIGHT 24
40 #define DEF_SCALABLE_DP 240
42 #define FF_FAMILY (FF_MODERN | FF_SWISS | FF_ROMAN | FF_DECORATIVE | FF_SCRIPT)
44 typedef struct __fontAlias
46 LPSTR faTypeFace;
47 LPSTR faAlias;
48 struct __fontAlias* next;
49 } fontAlias;
51 static fontAlias aliasTable[2] = {
52 { "Helvetica", "Helv", &aliasTable[1] },
53 { "Times", "Tms Rmn", NULL }
56 UINT16 XTextCaps = TC_OP_CHARACTER | TC_OP_STROKE | TC_CP_STROKE |
57 TC_SA_DOUBLE | TC_SA_INTEGER | TC_SA_CONTIN |
58 TC_UA_ABLE | TC_SO_ABLE | TC_RA_ABLE;
60 /* X11R6 adds TC_SF_X_YINDEP, maybe more... */
62 static const char* INIWinePrefix = "/.wine";
63 static const char* INIFontMetrics = "/.cachedmetrics";
64 static const char* INIFontSection = "fonts";
65 static const char* INISubSection = "Alias";
66 static const char* INIDefault = "Default";
68 static const char* LFDSeparator = "*-";
69 static const char* iso8859Encoding = "iso8859-";
70 static const char* iso646Encoding = "iso646.1991-";
71 static const char* ansiEncoding = "ansi-";
72 static fontResource* fontList = NULL;
73 static unsigned DefResolution = 0;
75 static fontObject* fontCache = NULL; /* array */
76 static int fontCacheSize = FONTCACHE;
77 static int fontLF = -1, fontMRU = -1; /* last free, most recently used */
79 #define __PFONT(pFont) ( fontCache + ((UINT32)(pFont) & 0x0000FFFF) )
80 #define CHECK_PFONT(pFont) ( (((UINT32)(pFont) & 0xFFFF0000) == X_PFONT_MAGIC) &&\
81 (((UINT32)(pFont) & 0x0000FFFF) < fontCacheSize) )
83 static INT32 XFONT_IsSubset(fontInfo*, fontInfo*);
84 static void XFONT_CheckFIList(fontResource*, fontInfo*, int subset_action);
85 static void XFONT_GrowFreeList(int start, int end);
87 /***********************************************************************
88 * Helper macros from X distribution
91 #define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
92 (((cs)->rbearing|(cs)->lbearing| \
93 (cs)->ascent|(cs)->descent) == 0))
95 #define CI_GET_CHAR_INFO(fs,col,def,cs) \
96 { \
97 cs = def; \
98 if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
99 if (fs->per_char == NULL) { \
100 cs = &fs->min_bounds; \
101 } else { \
102 cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
103 if (CI_NONEXISTCHAR(cs)) cs = def; \
108 #define CI_GET_DEFAULT_INFO(fs,cs) \
109 CI_GET_CHAR_INFO(fs, fs->default_char, NULL, cs)
111 /***********************************************************************
112 * Checksums
114 static UINT16 __lfCheckSum( LPLOGFONT16 plf )
116 CHAR font[LF_FACESIZE];
117 UINT16 checksum = 0;
118 UINT16 i;
120 #define ptr ((UINT16*)plf)
121 for( i = 0; i < 9; i++ ) checksum ^= *ptr++;
122 #undef ptr
123 i = 0;
124 #define ptr ((CHAR*)plf)
125 do { font[i++] = tolower(*ptr); } while (*ptr++);
126 for( ptr = font, i >>= 1; i > 0; i-- )
127 #undef ptr
128 #define ptr ((UINT16*)plf)
129 checksum ^= *ptr++;
130 #undef ptr
131 return checksum;
134 static UINT16 __genericCheckSum( UINT16* ptr, int size )
136 UINT16 checksum = 0;
137 unsigned i;
139 for( i = 0, size >>= 1; i < size; i++ ) checksum ^= *ptr++;
140 return checksum;
143 /*************************************************************************
144 * LFD parse/compose routines
146 static char* LFD_Advance(LPSTR lpFont, UINT16 uParmsNo)
148 int j = 0;
149 char* lpch = lpFont;
151 for( ; j < uParmsNo && *lpch; lpch++ ) if( *lpch == LFDSeparator[1] ) j++;
152 return lpch;
155 static void LFD_GetWeight( fontInfo* fi, LPSTR lpStr, int j)
157 if( j == 1 && *lpStr == '0' )
158 fi->fi_flags |= FI_POLYWEIGHT;
159 else if( j == 4 )
161 if( !lstrncmpi32A( "bold", lpStr, 4) )
162 fi->df.dfWeight = FW_BOLD;
163 else if( !lstrncmpi32A( "demi", lpStr, 4) )
165 fi->fi_flags |= FI_FW_DEMI;
166 fi->df.dfWeight = FW_DEMIBOLD;
168 else if( !lstrncmpi32A( "book", lpStr, 4) )
170 fi->fi_flags |= FI_FW_BOOK;
171 fi->df.dfWeight = FW_REGULAR;
174 else if( j == 5 )
176 if( !lstrncmpi32A( "light", lpStr, 5) )
177 fi->df.dfWeight = FW_LIGHT;
178 else if( !lstrncmpi32A( "black", lpStr, 5) )
179 fi->df.dfWeight = FW_BLACK;
181 else if( j == 6 && !lstrncmpi32A( "medium", lpStr, 6) )
182 fi->df.dfWeight = FW_REGULAR;
183 else if( j == 8 && !lstrncmpi32A( "demibold", lpStr, 8) )
184 fi->df.dfWeight = FW_DEMIBOLD;
185 else
186 fi->df.dfWeight = FW_DONTCARE; /* FIXME: try to get something
187 * from the weight property */
190 static int LFD_GetSlant( fontInfo* fi, LPSTR lpStr, int l)
192 if( l == 1 )
194 switch( tolower( *lpStr ) )
196 case '0': fi->fi_flags |= FI_POLYSLANT; /* haven't seen this one yet */
197 default:
198 case 'r': fi->df.dfItalic = 0;
199 break;
200 case 'o':
201 fi->fi_flags |= FI_OBLIQUE;
202 case 'i': fi->df.dfItalic = 1;
203 break;
205 return 0;
207 return 1;
210 /*************************************************************************
211 * LFD_InitFontInfo
213 * Fill in some fields in the fontInfo struct.
215 static int LFD_InitFontInfo( fontInfo* fi, LPSTR lpstr )
217 LPSTR lpch;
218 int i, j, dec_style_check, scalability;
219 UINT16 tmp[3];
221 memset(fi, 0, sizeof(fontInfo) );
223 /* weight name - */
224 lpch = LFD_Advance( lpstr, 1);
225 if( !*lpch ) return FALSE;
226 j = lpch - lpstr - 1;
227 LFD_GetWeight( fi, lpstr, j );
229 /* slant - */
230 lpch = LFD_Advance( lpstr = lpch, 1);
231 if( !*lpch ) return FALSE;
232 j = lpch - lpstr - 1;
233 dec_style_check = LFD_GetSlant( fi, lpstr, j );
235 /* width name - */
236 lpch = LFD_Advance( lpstr = lpch, 1);
237 if( !*lpch ) return FALSE;
238 if( lstrncmpi32A( "normal", lpstr, 6) ) /* XXX 'narrow', 'condensed', etc... */
239 dec_style_check = TRUE;
240 else
241 fi->fi_flags |= FI_NORMAL;
243 /* style - */
244 lpch = LFD_Advance( lpstr = lpch, 1);
245 if( !*lpch ) return FALSE;
246 j = lpch - lpstr - 1;
247 if( j > 3 ) /* find out is there "sans" or "script" */
249 j = 0;
250 *(lpch - 1) = '\0';
252 if( strstr(lpstr, "sans") )
254 fi->df.dfPitchAndFamily |= FF_SWISS;
255 j = 1;
257 if( strstr(lpstr, "script") )
259 fi->df.dfPitchAndFamily |= FF_SCRIPT;
260 j = 1;
262 if( !j && dec_style_check )
263 fi->df.dfPitchAndFamily |= FF_DECORATIVE;
264 *(lpch - 1) = LFDSeparator[1];
267 /* pixel height, decipoint height, and res_x */
269 for( i = scalability = 0; i < 3; i++ )
271 lpch = LFD_Advance( lpstr = lpch, 1);
272 if( !*lpch ) return FALSE;
273 if( lpch - lpstr == 1 || lpch - lpstr > 4 ) return FALSE; /* ridiculous */
275 *(lpch - 1) = '\0';
276 if( !(tmp[i] = atoi(lpstr)) ) scalability++;
277 *(lpch - 1) = LFDSeparator[1];
279 if( scalability == 3 ) /* Type1 */
281 fi->fi_flags |= FI_SCALABLE;
282 fi->lfd_height = DEF_SCALABLE_HEIGHT; fi->lfd_decipoints = DEF_SCALABLE_DP;
283 fi->lfd_resolution = DefResolution;
285 else if( scalability == 0 ) /* Bitmap */
287 fi->lfd_height = tmp[0]; fi->lfd_decipoints = tmp[1];
288 fi->lfd_resolution = tmp[2];
290 else return FALSE; /* #$%^!!! X11R6 mutant garbage */
292 /* res_y - skip, spacing - */
293 lpstr = LFD_Advance( lpch, 1);
294 switch( *lpstr )
296 case '\0': return FALSE;
298 case 'p': fi->fi_flags |= FI_VARIABLEPITCH;
299 break;
300 case 'c': fi->df.dfPitchAndFamily |= FF_MODERN;
301 fi->fi_flags |= FI_FIXEDEX;
302 /* fall through */
303 case 'm': fi->fi_flags |= FI_FIXEDPITCH;
304 break;
305 default:
306 fi->df.dfPitchAndFamily |= DEFAULT_PITCH | FF_DONTCARE;
308 lpstr = LFD_Advance(lpstr, 1);
309 if( !*lpstr ) return FALSE;
311 /* average width - */
312 lpch = LFD_Advance( lpstr, 1);
313 if( !*lpch ) return FALSE;
314 if( lpch - lpstr == 1 || lpch - lpstr > 4 ) return FALSE; /* ridiculous */
315 *(lpch - 1) = '\0';
316 if( !(fi->lfd_width = atoi(lpstr)) && !scalability ) return FALSE;
317 *(lpch - 1) = LFDSeparator[1];
319 /* charset registry, charset encoding - */
320 if( strstr(lpch, "jisx") || strstr(lpch, "ksc") ) return FALSE; /* 2-byte stuff */
322 if( strstr(lpch, iso8859Encoding) )
324 fi->fi_flags |= FI_ENC_ISO8859;
325 fi->df.dfCharSet = ANSI_CHARSET;
327 else if( strstr(lpch, iso646Encoding) )
329 fi->fi_flags |= FI_ENC_ISO646;
330 fi->df.dfCharSet = ANSI_CHARSET;
332 else if( strstr(lpch, ansiEncoding) ) /* font2bdf produces -ansi-0 LFD */
334 fi->fi_flags |= FI_ENC_ANSI;
335 fi->df.dfCharSet = ANSI_CHARSET;
337 else if( strstr(lpch, "fontspecific") )
338 fi->df.dfCharSet = SYMBOL_CHARSET;
339 else
340 fi->df.dfCharSet = OEM_CHARSET; /* FIXME: -cp126-.. from fnt2bdf */
342 return TRUE;
345 /*************************************************************************
346 * LFD_ComposeLFD
348 static BOOL32 LFD_ComposeLFD( fontObject* fo,
349 INT32 height, LPSTR lpLFD, UINT32 uRelax )
351 int h, w, ch, point = 0;
352 char* lpch;
353 const char* lpEncoding = NULL;
355 lstrcpy32A( lpLFD, fo->fr->resource );
357 /* add weight */
358 switch( fo->fi->df.dfWeight )
360 case FW_BOLD:
361 strcat( lpLFD, "bold" ); break;
362 case FW_REGULAR:
363 if( fo->fi->fi_flags & FI_FW_BOOK )
364 strcat( lpLFD, "book" );
365 else
366 strcat( lpLFD, "medium" );
367 break;
368 case FW_DEMIBOLD:
369 strcat( lpLFD, "demi" );
370 if( !( fo->fi->fi_flags & FI_FW_DEMI) )
371 strcat ( lpLFD, "bold" );
372 break;
373 case FW_BLACK:
374 strcat( lpLFD, "black" ); break;
375 case FW_LIGHT:
376 strcat( lpLFD, "light" ); break;
377 default:
378 strcat( lpLFD, "*" );
381 /* add slant */
382 if( fo->fi->df.dfItalic )
383 if( fo->fi->fi_flags & FI_OBLIQUE )
384 strcat( lpLFD, "-o" );
385 else
386 strcat( lpLFD, "-i" );
387 else
388 strcat( lpLFD, (uRelax < 4) ? "-r" : "-*" );
390 /* add width style and skip serifs */
391 if( fo->fi->fi_flags & FI_NORMAL )
392 strcat( lpLFD, "-normal-*-");
393 else
394 strcat( lpLFD, "-*-*-" );
396 /* add pixelheight, pointheight, and resolution
398 * FIXME: fill in lpXForm and lpPixmap for rotated fonts
400 if( fo->fo_flags & FO_SYNTH_HEIGHT ) h = fo->fi->lfd_height;
401 else h = (fo->fi->lfd_height * height) / fo->fi->df.dfPixHeight;
403 if( fo->lf.lfWidth && (XTextCaps & TC_SF_X_YINDEP)
404 && !(fo->fo_flags & FO_SYNTH_WIDTH) )
405 point = (fo->fi->lfd_decipoints * fo->lf.lfWidth) / fo->fi->df.dfAvgWidth;
407 /* spacing and width */
409 if( fo->fi->fi_flags & FI_FIXEDPITCH )
410 w = ( fo->fi->fi_flags & FI_FIXEDEX ) ? 'c' : 'm';
411 else
412 w = ( fo->fi->fi_flags & FI_VARIABLEPITCH ) ? 'p' : LFDSeparator[0];
414 /* encoding, not quite there yet */
416 if( fo->fi->df.dfCharSet == ANSI_CHARSET )
418 if( fo->fi->fi_flags & FI_ENC_ISO8859 )
419 lpEncoding = iso8859Encoding;
420 else if( fo->fi->fi_flags & FI_ENC_ISO646 )
421 lpEncoding = iso646Encoding;
422 else lpEncoding = ansiEncoding;
423 } else lpEncoding = LFDSeparator;
425 lpch = lpLFD + lstrlen32A(lpLFD);
426 ch = (fo->fi->fi_flags & FI_SCALABLE) ? '0' : LFDSeparator[0];
428 switch( uRelax )
430 /* RealizeFont() will call us repeatedly with increasing uRelax
431 * until XLoadFont() succeeds. */
433 case 0:
434 if( point )
436 sprintf( lpch, "%i-%i-%i-%c-%c-*-%s*", h, point,
437 fo->fi->lfd_resolution, ch, w, lpEncoding );
438 break;
440 /* fall through */
442 case 1:
443 sprintf( lpch, "%i-*-%i-%c-%c-*-%s*", h,
444 fo->fi->lfd_resolution, ch, w, lpEncoding );
445 break;
447 case 2:
448 sprintf( lpch, "%i-*-%i-%c-*-*-%s*",
449 h, fo->fi->lfd_resolution, ch, lpEncoding );
450 break;
452 case 3:
453 sprintf( lpch, "%i-*-%i-%c-*-*-%s*", fo->fi->lfd_height,
454 fo->fi->lfd_resolution, ch, lpEncoding );
455 break;
457 default:
458 sprintf( lpch, "%i-*-*-*-*-*-%s*", fo->fi->lfd_height, lpEncoding );
461 dprintf_font(stddeb,"\tLFD: %s\n", lpLFD );
462 return TRUE;
466 /***********************************************************************
467 * X Font Resources
469 * font info - http://www.microsoft.com/kb/articles/q65/1/23.htm
470 * Windows font metrics - http://www.microsoft.com/kb/articles/q32/6/67.htm
472 static BOOL32 XFONT_GetLeading( LPIFONTINFO16 pFI, XFontStruct* x_fs, INT32* pIL, INT32* pEL )
474 unsigned long height;
475 unsigned min = (unsigned char)pFI->dfFirstChar;
476 unsigned max = (unsigned char)pFI->dfLastChar;
477 BOOL32 bHaveCapHeight = (pFI->dfCharSet == ANSI_CHARSET && 'X' >= min && 'X' <= max );
479 if( pEL ) *pEL = 0;
480 if( XGetFontProperty(x_fs, XA_CAP_HEIGHT, &height) == False )
482 if( x_fs->per_char )
483 if( bHaveCapHeight )
484 height = x_fs->per_char['X' - min].ascent;
485 else
486 if (x_fs->ascent >= x_fs->max_bounds.ascent)
487 height = x_fs->max_bounds.ascent;
488 else
490 height = x_fs->ascent;
491 if( pEL )
492 *pEL = x_fs->max_bounds.ascent - height;
494 else
495 height = x_fs->min_bounds.ascent;
498 *pIL = x_fs->ascent - height;
499 return (bHaveCapHeight && x_fs->per_char);
502 static INT32 XFONT_GetAvgCharWidth( LPIFONTINFO16 pFI, XFontStruct* x_fs)
504 unsigned min = (unsigned char)pFI->dfFirstChar;
505 unsigned max = (unsigned char)pFI->dfLastChar;
507 if( x_fs->per_char )
509 int width, chars, j;
510 for( j = 0, width = 0, chars = 0, max -= min; j <= max; j++ )
511 if( !CI_NONEXISTCHAR(x_fs->per_char + j) )
513 width += x_fs->per_char[j].width;
514 chars++;
516 return (width / chars);
518 /* uniform width */
519 return x_fs->min_bounds.width;
522 /***********************************************************************
523 * XFONT_SetFontMetric
525 * Initializes IFONTINFO16. dfHorizRes and dfVertRes must be already set.
527 static void XFONT_SetFontMetric(fontInfo* fi, fontResource* fr, XFontStruct* xfs)
529 unsigned min, max;
530 INT32 el, il;
532 fi->df.dfFirstChar = (BYTE)(min = xfs->min_char_or_byte2);
533 fi->df.dfLastChar = (BYTE)(max = xfs->max_char_or_byte2);
535 fi->df.dfDefaultChar = (BYTE)xfs->default_char;
536 fi->df.dfBreakChar = (BYTE)(( ' ' < min || ' ' > max) ? xfs->default_char: ' ');
538 fi->df.dfPixHeight = (INT16)((fi->df.dfAscent = (INT16)xfs->ascent) + xfs->descent);
539 fi->df.dfPixWidth = (xfs->per_char) ? 0 : xfs->min_bounds.width;
540 fi->df.dfMaxWidth = (INT16)abs(xfs->max_bounds.width);
542 if( XFONT_GetLeading( &fi->df, xfs, &il, &el ) )
543 fi->df.dfAvgWidth = (INT16)xfs->per_char['X' - min].width;
544 else
545 fi->df.dfAvgWidth = (INT16)XFONT_GetAvgCharWidth( &fi->df, xfs);
547 fi->df.dfInternalLeading = (INT16)il;
548 fi->df.dfExternalLeading = (INT16)el;
550 fi->df.dfPoints = (INT16)(((INT32)(fi->df.dfPixHeight -
551 fi->df.dfInternalLeading) * 72) / fi->df.dfVertRes);
553 if( xfs->min_bounds.width != xfs->max_bounds.width )
554 fi->df.dfPitchAndFamily |= TMPF_FIXED_PITCH; /* au contraire! */
555 if( fi->fi_flags & FI_SCALABLE )
557 fi->df.dfType = DEVICE_FONTTYPE;
558 fi->df.dfPitchAndFamily |= TMPF_DEVICE;
560 else if( fi->fi_flags & FI_TRUETYPE )
561 fi->df.dfType = TRUETYPE_FONTTYPE;
562 else
563 fi->df.dfType = RASTER_FONTTYPE;
565 fi->df.dfFace = fr->lfFaceName;
568 /***********************************************************************
569 * XFONT_GetTextMetric
571 static void XFONT_GetTextMetric( fontObject* pfo, LPTEXTMETRIC32A pTM )
573 LPIFONTINFO16 pdf = &pfo->fi->df;
575 pTM->tmAscent = pfo->fs->ascent;
576 pTM->tmDescent = pfo->fs->descent;
577 pTM->tmHeight = pTM->tmAscent + pTM->tmDescent;
579 pTM->tmAveCharWidth = pfo->foAvgCharWidth;
580 pTM->tmMaxCharWidth = abs(pfo->fs->max_bounds.width);
582 pTM->tmInternalLeading = pfo->foInternalLeading;
583 pTM->tmExternalLeading = pdf->dfExternalLeading;
585 pTM->tmStruckOut = (pfo->fo_flags & FO_SYNTH_STRIKEOUT )
586 ? 1 : pdf->dfStrikeOut;
587 pTM->tmUnderlined = (pfo->fo_flags & FO_SYNTH_UNDERLINE )
588 ? 1 : pdf->dfUnderline;
590 pTM->tmOverhang = 0;
591 if( pfo->fo_flags & FO_SYNTH_ITALIC )
593 pTM->tmOverhang += pTM->tmHeight/3;
594 pTM->tmItalic = 1;
595 } else
596 pTM->tmItalic = pdf->dfItalic;
598 pTM->tmWeight = pdf->dfWeight;
599 if( pfo->fo_flags & FO_SYNTH_BOLD )
601 pTM->tmOverhang++;
602 pTM->tmWeight += 100;
605 *(INT32*)&pTM->tmFirstChar = *(INT32*)&pdf->dfFirstChar;
607 pTM->tmCharSet = pdf->dfCharSet;
608 pTM->tmPitchAndFamily = pdf->dfPitchAndFamily;
610 pTM->tmDigitizedAspectX = pdf->dfHorizRes;
611 pTM->tmDigitizedAspectY = pdf->dfVertRes;
614 /***********************************************************************
615 * XFONT_GetFontMetric
617 * Retrieve font metric info (enumeration).
619 static UINT32 XFONT_GetFontMetric( fontInfo* pfi, LPENUMLOGFONTEX16 pLF,
620 LPNEWTEXTMETRIC16 pTM )
622 memset( pLF, 0, sizeof(*pLF) );
623 memset( pTM, 0, sizeof(*pTM) );
625 #define plf ((LPLOGFONT16)pLF)
626 plf->lfHeight = pTM->tmHeight = pfi->df.dfPixHeight;
627 plf->lfWidth = pTM->tmAveCharWidth = pfi->df.dfAvgWidth;
628 plf->lfWeight = pTM->tmWeight = pfi->df.dfWeight;
629 plf->lfItalic = pTM->tmItalic = pfi->df.dfItalic;
630 plf->lfUnderline = pTM->tmUnderlined = pfi->df.dfUnderline;
631 plf->lfStrikeOut = pTM->tmStruckOut = pfi->df.dfStrikeOut;
632 plf->lfCharSet = pTM->tmCharSet = pfi->df.dfCharSet;
634 /* convert pitch values */
636 pTM->tmPitchAndFamily = pfi->df.dfPitchAndFamily;
637 plf->lfPitchAndFamily = (pfi->df.dfPitchAndFamily & 0xF1) + 1;
639 lstrcpyn32A( plf->lfFaceName, pfi->df.dfFace, LF_FACESIZE );
640 #undef plf
642 pTM->tmAscent = pfi->df.dfAscent;
643 pTM->tmDescent = pTM->tmHeight - pTM->tmAscent;
644 pTM->tmInternalLeading = pfi->df.dfInternalLeading;
645 pTM->tmMaxCharWidth = pfi->df.dfMaxWidth;
646 pTM->tmDigitizedAspectX = pfi->df.dfHorizRes;
647 pTM->tmDigitizedAspectY = pfi->df.dfVertRes;
649 *(INT32*)&pTM->tmFirstChar = *(INT32*)&pfi->df.dfFirstChar;
651 /* return font type */
653 return pfi->df.dfType;
657 /***********************************************************************
658 * XFONT_FixupFlags
660 * dfPitchAndFamily flags for some common typefaces.
662 static BYTE XFONT_FixupFlags( LPCSTR lfFaceName )
664 switch( lfFaceName[0] )
666 case 'h':
667 case 'H': if(!lstrcmpi32A(lfFaceName, "Helvetica") )
668 return FF_SWISS;
669 break;
670 case 'c':
671 case 'C': if(!lstrcmpi32A(lfFaceName, "Courier") )
672 return FF_ROMAN;
673 break;
674 case 'p':
675 case 'P': if( !lstrcmpi32A(lfFaceName,"Palatino") )
676 return FF_ROMAN;
677 break;
678 case 't':
679 case 'T': if(!lstrncmpi32A(lfFaceName, "Times", 5) )
680 return FF_ROMAN;
681 break;
682 case 'u':
683 case 'U': if(!lstrcmpi32A(lfFaceName, "Utopia") )
684 return FF_ROMAN;
685 break;
686 case 'z':
687 case 'Z': if(!lstrcmpi32A(lfFaceName, "Zapf Dingbats") )
688 return FF_DECORATIVE;
690 return 0;
694 /***********************************************************************
695 * XFONT_WindowsNames
697 * Build generic Windows aliases for X font names.
699 * -misc-fixed- -> "Fixed"
700 * -sony-fixed- -> "Sony Fixed", etc...
702 static void XFONT_WindowsNames( char* buffer )
704 fontResource* fr, *pfr;
705 char* lpstr, *lpch;
706 int i, up;
707 BYTE bFamilyStyle;
709 for( fr = fontList; fr ; fr = fr->next )
711 if( fr->fr_flags & FR_NAMESET ) continue; /* skip already assigned */
713 lpstr = LFD_Advance(fr->resource, 2);
714 i = lpstr - LFD_Advance( lpstr, 1 );
716 for( pfr = fontList; pfr != fr ; pfr = pfr->next )
717 if( pfr->fr_flags & FR_NAMESET )
719 lpch = LFD_Advance(pfr->resource, 2);
721 /* check if already have the same face name */
723 if( !lstrncmp32A(lpch, lpstr, i) ) break;
725 if( pfr != fr ) /* prepend vendor name */
726 lpstr = fr->resource + 1;
728 for( i = 0, up = 1, lpch = fr->lfFaceName; *lpstr && i < 32;
729 lpch++, lpstr++, i++ )
731 if( *lpstr == LFDSeparator[1] || *lpstr == ' ' )
733 *lpch = ' ';
734 up = 1; continue;
736 else if( isalpha(*lpstr) && up )
738 *lpch = toupper(*lpstr);
739 up = 0; continue;
741 *lpch = *lpstr;
743 while (*(lpch - 1) == ' ') *(--lpch) = '\0';
745 if( (bFamilyStyle = XFONT_FixupFlags( fr->lfFaceName )) )
747 fontInfo* fi;
748 for( fi = fr->fi ; fi ; fi = fi->next )
749 fi->df.dfPitchAndFamily |= bFamilyStyle;
752 #ifdef DEBUG_FONT_INIT
753 dprintf_font(stddeb,"typeface \'%s\'\n", fr->lfFaceName);
754 #endif
755 fr->fr_flags |= FR_NAMESET;
758 if( PROFILE_GetWineIniString( INIFontSection, INIDefault, "", buffer, 128 ) )
760 while( *buffer && isspace(*buffer) ) buffer++;
761 for( fr = NULL, pfr = fontList; pfr; pfr = pfr->next )
763 i = lstrlen32A( pfr->resource );
764 if( !lstrncmpi32A( pfr->resource, buffer, i) )
766 if( fr )
768 fr->next = pfr->next;
769 pfr->next = fontList;
770 fontList = pfr;
772 break;
774 fr = pfr;
779 /***********************************************************************
780 * XFONT_CreateAlias
782 static fontAlias* XFONT_CreateAlias( LPCSTR lpTypeFace, LPCSTR lpAlias )
784 fontAlias* pfa = aliasTable;
785 int j = lstrlen32A(lpTypeFace) + 1;
787 while( pfa->next ) pfa = pfa->next;
788 pfa->next = HeapAlloc( SystemHeap, 0, sizeof(fontAlias) +
789 j + lstrlen32A(lpAlias) + 1 );
790 if((pfa = pfa->next))
792 pfa->next = NULL;
793 pfa->faTypeFace = (LPSTR)(pfa + 1);
794 lstrcpy32A( pfa->faTypeFace, lpTypeFace );
795 pfa->faAlias = pfa->faTypeFace + j;
796 lstrcpy32A( pfa->faAlias, lpAlias );
798 #ifdef DEBUG_FONT_INIT
799 dprintf_font(stddeb, "\tadded alias '%s' for %s\n", lpAlias, lpTypeFace );
800 #endif
801 return pfa;
803 return NULL;
806 /***********************************************************************
807 * XFONT_LoadAliases
809 * Read user-defined aliases from wine.conf. Format is as follows
811 * Alias# = [Windows font name],[LFD font name], <substitute original name>
813 * Example:
814 * Alias0 = Arial, -adobe-helvetica-
815 * Alias1 = Times New Roman, -bitstream-courier-, 1
816 * ...
818 static void XFONT_LoadAliases( char** buffer, int buf_size )
820 char subsection[32];
821 int i = 0;
823 if( buf_size < 128 )
824 *buffer = HeapReAlloc(SystemHeap, 0, *buffer, 256 );
827 wsprintf32A( subsection, "%s%i", INISubSection, i++ );
829 if( PROFILE_GetWineIniString( INIFontSection, subsection, "", *buffer, 128 ) )
831 char* lpchX, *lpchW = *buffer;
833 while( isspace(*lpchW) ) lpchW++;
834 lpchX = PROFILE_GetStringItem( lpchW );
836 if( lpchX )
838 fontResource* fr;
840 for (fr = fontList; fr ; fr = fr->next)
842 int j;
844 j = lstrlen32A( fr->resource );
846 if( !lstrncmpi32A( fr->resource, lpchX, j) )
848 char* lpch = PROFILE_GetStringItem( lpchX );
850 if( lpch )
852 #ifdef DEBUG_FONT_INIT
853 dprintf_font(stddeb, "\tsubstituted '%s' with %s\n",
854 fr->lfFaceName, lpchW );
855 #endif
856 lstrcpyn32A( fr->lfFaceName, lpchW, LF_FACESIZE );
857 fr->fr_flags |= FR_NAMESET;
859 else
861 /* create new entry in the alias table */
862 XFONT_CreateAlias(fr->lfFaceName, lpchW);
864 break;
868 else fprintf(stderr, "XFONT_Init: malformed font alias '%s'\n", *buffer );
870 else break;
871 } while(TRUE);
874 /***********************************************************************
875 * XFONT_UserMetricsCache
877 * Returns expanded name for the ~/.wine/.cachedmetrics file.
879 static char* XFONT_UserMetricsCache( char* buffer, int* buf_size )
881 struct passwd* pwd;
883 pwd = getpwuid(getuid());
884 if( pwd && pwd->pw_dir )
886 int i = lstrlen32A( pwd->pw_dir ) + lstrlen32A( INIWinePrefix ) + lstrlen32A( INIFontMetrics ) + 2;
887 if( i > *buf_size ) buffer = (char*) HeapReAlloc( SystemHeap, 0, buffer, *buf_size = i );
888 lstrcpy32A( buffer, pwd->pw_dir );
889 strcat( buffer, INIWinePrefix );
890 strcat( buffer, INIFontMetrics );
891 } else buffer[0] = '\0';
892 return buffer;
896 /***********************************************************************
897 * XFONT_ReadCachedMetrics
899 static BOOL32 XFONT_ReadCachedMetrics( int fd, unsigned x_checksum, int x_count )
901 if( fd >= 0 )
903 unsigned u;
904 int i, j;
906 /* read checksums */
907 read( fd, &u, sizeof(unsigned) );
908 read( fd, &i, sizeof(int) );
910 if( u == x_checksum && i == x_count )
912 off_t length, offset = 3 * sizeof(int);
914 /* read total size */
915 read( fd, &i, sizeof(int) );
916 length = lseek( fd, 0, SEEK_END );
918 if( length == (i + offset) )
920 lseek( fd, offset, SEEK_SET );
921 fontList = (fontResource*)HeapAlloc( SystemHeap, 0, i);
922 if( fontList )
924 fontResource* pfr = fontList;
925 fontInfo* pfi = NULL;
927 dprintf_font(stddeb,"Reading cached font metrics:\n");
929 read( fd, fontList, i); /* read all metrics at once */
930 while( offset < length )
932 offset += sizeof(fontResource) + sizeof(fontInfo);
933 pfr->fi = pfi = (fontInfo*)(pfr + 1);
934 j = 1;
935 while( TRUE )
937 if( offset > length ||
938 (int)(pfi->next) != j++ ) goto fail;
940 pfi->df.dfFace = pfr->lfFaceName;
941 pfi->next = pfi + 1;
943 if( j > pfr->count ) break;
945 pfi = pfi->next;
946 offset += sizeof(fontInfo);
948 pfi->next = NULL;
949 if( pfr->next )
951 pfr->next = (fontResource*)(pfi + 1);
952 pfr = pfr->next;
954 else break;
956 if( pfr->next == NULL &&
957 *(int*)(pfi + 1) == X_FMC_MAGIC )
959 /* read LFD stubs */
960 char* lpch = (char*)((int*)(pfi + 1) + 1);
961 offset += sizeof(int);
962 for( pfr = fontList; pfr; pfr = pfr->next )
964 dprintf_font(stddeb,"\t%s, %i instances\n", lpch, pfr->count );
965 pfr->resource = lpch;
966 while( TRUE )
968 if( ++offset > length ) goto fail;
969 if( !*lpch++ ) break;
972 close( fd );
973 return TRUE;
978 fail:
979 if( fontList ) HeapFree( SystemHeap, 0, fontList );
980 fontList = NULL;
981 close( fd );
983 return FALSE;
986 /***********************************************************************
987 * XFONT_WriteCachedMetrics
989 static BOOL32 XFONT_WriteCachedMetrics( int fd, unsigned x_checksum, int x_count, int n_ff )
991 fontResource* pfr;
992 fontInfo* pfi;
994 if( fd >= 0 )
996 int i, j, k;
998 /* font metrics file:
1000 * +0000 x_checksum
1001 * +0004 x_count
1002 * +0008 total size to load
1003 * +000C prepackaged font metrics
1004 * ...
1005 * +...x X_FMC_MAGIC
1006 * +...x + 4 LFD stubs
1009 write( fd, &x_checksum, sizeof(unsigned) );
1010 write( fd, &x_count, sizeof(int) );
1012 for( j = i = 0, pfr = fontList; pfr; pfr = pfr->next )
1014 i += lstrlen32A( pfr->resource ) + 1;
1015 j += pfr->count;
1017 i += n_ff * sizeof(fontResource) + j * sizeof(fontInfo) + sizeof(int);
1018 write( fd, &i, sizeof(int) );
1020 dprintf_font(stddeb,"Writing font cache:\n");
1022 for( pfr = fontList; pfr; pfr = pfr->next )
1024 fontInfo fi;
1026 dprintf_font(stddeb,"\t%s, %i instances\n", pfr->resource, pfr->count );
1028 i = write( fd, pfr, sizeof(fontResource) );
1029 if( i == sizeof(fontResource) )
1031 for( k = 1, pfi = pfr->fi; pfi; pfi = pfi->next )
1033 memcpy( &fi, pfi, sizeof(fi) );
1035 fi.df.dfFace = NULL;
1036 fi.next = (fontInfo*)k; /* loader checks this */
1038 j = write( fd, &fi, sizeof(fi) );
1039 k++;
1041 if( j == sizeof(fontInfo) ) continue;
1043 break;
1045 if( i == sizeof(fontResource) && j == sizeof(fontInfo) )
1047 i = j = X_FMC_MAGIC;
1048 write( fd, &i, sizeof(int) );
1049 for( pfr = fontList; pfr && i == j; pfr = pfr->next )
1051 i = lstrlen32A( pfr->resource ) + 1;
1052 j = write( fd, pfr->resource, i );
1055 close( fd );
1056 return ( i == j );
1058 return TRUE;
1061 /***********************************************************************
1062 * X11DRV_FONT_Init
1064 * Initialize font resource list and allocate font cache.
1066 BOOL32 X11DRV_FONT_Init( DeviceCaps* pDevCaps )
1068 XFontStruct* x_fs;
1069 fontResource* fr, *pfr;
1070 fontInfo* fi, *pfi;
1071 unsigned x_checksum;
1072 int i, j, k, x_count, fd = -1, buf_size = 0;
1073 char* lpstr, *lpch, *lpmetrics, *buffer;
1074 char** x_pattern;
1076 DefResolution = PROFILE_GetWineIniInt( INIFontSection, "Resolution", 0 );
1077 if( !DefResolution ) DefResolution = pDevCaps->logPixelsY;
1079 i = abs(DefResolution - 72);
1080 j = abs(DefResolution - 75);
1081 k = abs(DefResolution - 100);
1083 if( i < j ) DefResolution = ( i < k ) ? 72 : 100;
1084 else DefResolution = ( j < k ) ? 75 : 100;
1086 x_pattern = XListFonts(display, "*", MAX_FONT_FAMILIES * 16, &x_count );
1088 dprintf_font(stddeb,"Font Mapper: initializing %i fonts [LPY=%i, DR=%i]\n",
1089 x_count, pDevCaps->logPixelsY, DefResolution);
1090 for( i = x_checksum = 0; i < x_count; i++ )
1092 #if 0
1093 printf("%i\t: %s\n", i, x_pattern[i] );
1094 #endif
1096 j = lstrlen32A( x_pattern[i] );
1097 if( j ) x_checksum ^= __genericCheckSum( (UINT16*)(x_pattern[i]), j );
1099 x_checksum |= X_PFONT_MAGIC;
1101 buf_size = 128;
1102 buffer = HeapAlloc( SystemHeap, 0, buf_size );
1103 lpmetrics = NULL;
1105 /* deal with systemwide font metrics cache */
1107 if( PROFILE_GetWineIniString( INIFontSection, "FontMetrics", "", buffer, 128 ) )
1108 fd = open( buffer, O_RDONLY );
1110 if( XFONT_ReadCachedMetrics(fd, x_checksum, x_count) == FALSE )
1112 /* try per-user */
1113 buffer = XFONT_UserMetricsCache( buffer, &buf_size );
1114 if( buffer[0] )
1116 fd = open( buffer, O_RDONLY );
1117 if( XFONT_ReadCachedMetrics(fd, x_checksum, x_count) == FALSE )
1118 lpmetrics = HEAP_strdupA( SystemHeap, 0, buffer ); /* update later on */
1122 fi = NULL;
1123 if( fontList == NULL ) /* build metrics from scratch */
1125 int n_ff;
1126 char* typeface;
1128 for( i = n_ff = 0; i < x_count; i++ )
1130 typeface = lpch = x_pattern[i];
1132 lpch = LFD_Advance(typeface, 3); /* extra '-' in the beginning */
1133 if( !*lpch ) continue;
1135 lpstr = lpch;
1136 j = lpch - typeface; /* resource name length */
1138 /* find a family to insert into */
1140 for( pfr = NULL, fr = fontList; fr; fr = fr->next )
1142 if( !lstrncmpi32A(fr->resource, typeface, j) &&
1143 lstrlen32A(fr->resource) == j ) break;
1144 pfr = fr;
1147 if( !fi ) fi = (fontInfo*) HeapAlloc(SystemHeap, 0, sizeof(fontInfo));
1149 if( !fr ) /* add new family */
1151 if( n_ff >= MAX_FONT_FAMILIES ) break;
1152 if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1154 n_ff++;
1155 fr = (fontResource*) HeapAlloc(SystemHeap, 0, sizeof(fontResource));
1156 memset(fr, 0, sizeof(fontResource));
1157 fr->resource = (char*) HeapAlloc(SystemHeap, 0, j + 1 );
1158 lstrcpyn32A( fr->resource, typeface, j + 1 );
1160 #ifdef DEBUG_FONT_INIT
1161 dprintf_font(stddeb," family: %s\n", fr->resource );
1162 #endif
1164 if( pfr ) pfr->next = fr;
1165 else fontList = fr;
1167 else if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1169 /* check if we already have something better than "fi" */
1171 for( pfi = fr->fi, j = 0; pfi && j <= 0; pfi = pfi->next )
1172 if( (j = XFONT_IsSubset( pfi, fi )) < 0 )
1173 pfi->fi_flags |= FI_SUBSET; /* superseded by "fi" */
1174 if( j > 0 ) continue;
1176 /* add new font instance "fi" to the "fr" font resource */
1178 if( fi->fi_flags & FI_SCALABLE )
1180 /* set scalable font height to 24 to get an origin for extrapolation */
1182 j = lstrlen32A(typeface); j += 0x10;
1183 if( j > buf_size )
1184 buffer = (char*)HeapReAlloc( SystemHeap, 0, buffer, buf_size = j );
1186 lpch = LFD_Advance(typeface, 7);
1187 memcpy( buffer, typeface, (j = lpch - typeface) );
1188 lpch = LFD_Advance(lpch, 4);
1189 sprintf( buffer + j, "%d-%d-%d-*-%c-*-", fi->lfd_height,
1190 fi->lfd_decipoints, fi->lfd_resolution,
1191 (*lpch == '-')?'*':*lpch );
1192 lpch = LFD_Advance(lpch, 2);
1193 strcat( lpstr = buffer, lpch);
1195 else lpstr = typeface;
1197 if( (x_fs = XLoadQueryFont(display, lpstr)) )
1199 fi->df.dfHorizRes = pDevCaps->logPixelsX;
1200 fi->df.dfVertRes = pDevCaps->logPixelsY;
1202 XFONT_SetFontMetric( fi, fr, x_fs );
1203 XFreeFont( display, x_fs );
1205 #ifdef DEBUG_FONT_INIT
1206 dprintf_font(stddeb,"\t[% 2ipt] '%s'\n", fi->df.dfPoints, typeface );
1207 #endif
1208 XFONT_CheckFIList( fr, fi, REMOVE_SUBSETS );
1209 fi = NULL; /* preventing reuse */
1211 else
1213 fprintf(stderr, "FONT_Init: failed to load %s\n", lpstr );
1215 XFONT_CheckFIList( fr, fi, UNMARK_SUBSETS );
1219 if( lpmetrics ) /* update cached metrics */
1221 fd = open( lpmetrics, O_CREAT | O_TRUNC | O_RDWR, 0644 ); /* -rw-r--r-- */
1222 if( XFONT_WriteCachedMetrics( fd, x_checksum, x_count, n_ff ) == FALSE )
1223 if( fd ) remove( lpmetrics ); /* couldn't write entire file */
1224 HeapFree( SystemHeap, 0, lpmetrics );
1228 if( fi ) HeapFree(SystemHeap, 0, fi);
1229 XFreeFontNames(x_pattern);
1231 /* check if we're dealing with X11 R6 server */
1233 lstrcpy32A(buffer, "-*-*-*-*-normal-*-[12 0 0 12]-*-72-*-*-*-iso8859-1");
1234 if( (x_fs = XLoadQueryFont(display, buffer)) )
1236 XTextCaps |= TC_SF_X_YINDEP;
1237 XFreeFont(display, x_fs);
1240 XFONT_WindowsNames( buffer );
1241 XFONT_LoadAliases( &buffer, buf_size );
1242 HeapFree(SystemHeap, 0, buffer);
1245 /* fontList initialization is over, allocate X font cache */
1247 fontCache = (fontObject*) HeapAlloc(SystemHeap, 0, fontCacheSize * sizeof(fontObject));
1248 XFONT_GrowFreeList(0, fontCacheSize - 1);
1250 #ifdef DEBUG_FONT_INIT
1251 dprintf_font(stddeb,"done!\n");
1252 #endif
1254 /* update text caps parameter */
1256 pDevCaps->textCaps = XTextCaps;
1257 return TRUE;
1261 /***********************************************************************
1262 * X Font Matching
1264 * Compare two fonts (only parameters set by the XFONT_InitFontInfo()).
1266 static INT32 XFONT_IsSubset(fontInfo* match, fontInfo* fi)
1268 INT32 m;
1270 /* 0 - keep both, 1 - keep match, -1 - keep fi */
1272 m = (BYTE*)&fi->df.dfPixWidth - (BYTE*)&fi->df.dfItalic;
1273 if( memcmp(&match->df.dfItalic, &fi->df.dfItalic, m )) return 0;
1275 if( (!((fi->fi_flags & FI_SCALABLE) + (match->fi_flags & FI_SCALABLE))
1276 && fi->lfd_height != match->lfd_height) ||
1277 (!((fi->fi_flags & FI_POLYWEIGHT) + (match->fi_flags & FI_POLYWEIGHT))
1278 && fi->df.dfWeight != match->df.dfWeight) ) return 0;
1280 m = (int)(match->fi_flags & (FI_POLYWEIGHT | FI_SCALABLE)) -
1281 (int)(fi->fi_flags & (FI_SCALABLE | FI_POLYWEIGHT));
1283 if( m == (FI_POLYWEIGHT - FI_SCALABLE) ||
1284 m == (FI_SCALABLE - FI_POLYWEIGHT) ) return 0; /* keep both */
1285 else if( m >= 0 ) return 1; /* 'match' is better */
1287 return -1; /* 'fi' is better */
1290 /***********************************************************************
1291 * XFONT_Match
1293 * Compute the matching score between the logical font and the device font.
1295 * contributions from highest to lowest:
1296 * charset
1297 * fixed pitch
1298 * height
1299 * family flags (only when the facename is not present)
1300 * width
1301 * weight, italics, underlines, strikeouts
1303 * NOTE: you can experiment with different penalty weights to see what happens.
1304 * http://premium.microsoft.com/msdn/library/techart/f30/f34/f40/d4d/sa8bf.htm
1306 static UINT32 XFONT_Match( fontMatch* pfm )
1308 fontInfo* pfi = pfm->pfi; /* device font to match */
1309 LPLOGFONT16 plf = pfm->plf; /* wanted logical font */
1310 UINT32 penalty = 0;
1311 BOOL32 bR6 = pfm->flags & FO_MATCH_XYINDEP; /* from TextCaps */
1312 BOOL32 bScale = pfi->fi_flags & FI_SCALABLE;
1313 INT32 d, h;
1315 dprintf_font( stddeb,"\t[ %-2ipt h=%-3i w=%-3i %s%s]", pfi->df.dfPoints,
1316 pfi->df.dfPixHeight, pfi->df.dfAvgWidth,
1317 (pfi->df.dfWeight > 400) ? "Bold " : "Normal ",
1318 (pfi->df.dfItalic) ? "Italic" : "" );
1320 pfm->flags = 0;
1322 if( plf->lfCharSet == DEFAULT_CHARSET )
1324 if( (pfi->df.dfCharSet!= ANSI_CHARSET) && (pfi->df.dfCharSet!=DEFAULT_CHARSET) ) penalty += 0x200;
1326 else if (plf->lfCharSet != pfi->df.dfCharSet) penalty += 0x200;
1328 /* TMPF_FIXED_PITCH means exactly the opposite */
1330 if( plf->lfPitchAndFamily & FIXED_PITCH )
1332 if( pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH ) penalty += 0x100;
1334 else if( !(pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH) ) penalty += 0x2;
1336 if( plf->lfHeight > 0 )
1337 d = (h = pfi->df.dfPixHeight) - plf->lfHeight;
1338 else if( plf->lfHeight < -1 )
1339 d = (h = pfi->df.dfPoints) + plf->lfHeight;
1340 else d = h = 0;
1342 if( d && plf->lfHeight )
1344 UINT16 height = ( plf->lfHeight > 0 ) ? plf->lfHeight
1345 : ((-plf->lfHeight * pfi->df.dfPixHeight) / h);
1346 if( bScale ) pfm->height = height;
1347 else if( (plf->lfQuality != PROOF_QUALITY) && bR6 )
1349 if( d > 0 ) /* do not shrink raster fonts */
1351 pfm->height = pfi->df.dfPixHeight;
1352 penalty += (pfi->df.dfPixHeight - height) * 0x4;
1354 else /* expand only in integer multiples */
1356 pfm->height = height - height%pfi->df.dfPixHeight;
1357 penalty += (height - pfm->height) * pfm->height / height;
1360 else /* can't be scaled at all */
1362 if( plf->lfQuality != PROOF_QUALITY) pfm->flags |= FO_SYNTH_HEIGHT;
1363 pfm->height = pfi->df.dfPixHeight;
1364 penalty += (d > 0)? d * 0x8 : -d * 0x10;
1366 } else pfm->height = pfi->df.dfPixHeight;
1368 if((pfm->flags & FO_MATCH_PAF) &&
1369 (plf->lfPitchAndFamily & FF_FAMILY) != (pfi->df.dfPitchAndFamily & FF_FAMILY) )
1370 penalty += 0x10;
1372 if( plf->lfWidth )
1374 if( bR6 && bScale ) h = 0;
1375 else
1377 /* FIXME: not complete */
1379 pfm->flags |= FO_SYNTH_WIDTH;
1380 h = abs(plf->lfWidth - (pfm->height * pfi->df.dfAvgWidth)/pfi->df.dfPixHeight);
1382 penalty += h * ( d ) ? 0x2 : 0x1 ;
1384 else if( !(pfi->fi_flags & FI_NORMAL) ) penalty++;
1386 if( pfi->lfd_resolution != DefResolution ) penalty++;
1388 if( plf->lfWeight != FW_DONTCARE )
1390 penalty += abs(plf->lfWeight - pfi->df.dfWeight) / 40;
1391 if( plf->lfWeight > pfi->df.dfWeight ) pfm->flags |= FO_SYNTH_BOLD;
1392 } else if( pfi->df.dfWeight >= FW_BOLD ) penalty++; /* choose normal by default */
1394 if( plf->lfItalic != pfi->df.dfItalic )
1396 penalty += 0x4;
1397 pfm->flags |= FO_SYNTH_ITALIC;
1400 if( plf->lfUnderline ) pfm->flags |= FO_SYNTH_UNDERLINE;
1401 if( plf->lfStrikeOut ) pfm->flags |= FO_SYNTH_STRIKEOUT;
1403 dprintf_font(stddeb,"-> %i\n", penalty );
1405 return penalty;
1408 /***********************************************************************
1409 * XFONT_MatchFIList
1411 * Scan a particular font resource for the best match.
1413 static UINT32 XFONT_MatchFIList( fontMatch* pfm )
1415 BOOL32 skipRaster = (pfm->flags & FO_MATCH_NORASTER);
1416 UINT32 current_score, score = (UINT32)(-1);
1417 fontMatch fm = *pfm;
1419 for( fm.pfi = pfm->pfr->fi; fm.pfi && score; fm.pfi = fm.pfi->next )
1421 if( skipRaster && !(fm.pfi->fi_flags & FI_SCALABLE) )
1422 continue;
1424 current_score = XFONT_Match( &fm );
1425 if( score > current_score )
1427 memcpy( pfm, &fm, sizeof(fontMatch) );
1428 score = current_score;
1431 return score;
1434 /***********************************************************************
1435 * XFONT_CheckAliasTable
1437 static LPSTR XFONT_CheckAliasTable( LPSTR lpAlias )
1439 fontAlias* fa;
1441 for( fa = aliasTable; fa; fa = fa->next )
1442 if( !lstrcmpi32A( fa->faAlias, lpAlias ) ) return fa->faTypeFace;
1443 return NULL;
1446 /***********************************************************************
1447 * XFONT_CheckFIList
1449 * REMOVE_SUBSETS - attach new fi and purge subsets
1450 * UNMARK_SUBSETS - remove subset flags from all fi entries
1452 static void XFONT_CheckFIList( fontResource* fr, fontInfo* fi, int action)
1454 int i = 0;
1455 fontInfo* pfi, *prev;
1457 for( prev = NULL, pfi = fr->fi; pfi; )
1459 if( action == REMOVE_SUBSETS )
1461 if( pfi->fi_flags & FI_SUBSET )
1463 fontInfo* subset = pfi;
1465 i++;
1466 fr->count--;
1467 if( prev ) prev->next = pfi = pfi->next;
1468 else fr->fi = pfi = pfi->next;
1469 HeapFree( SystemHeap, 0, subset );
1470 continue;
1473 else pfi->fi_flags &= ~FI_SUBSET;
1475 prev = pfi;
1476 pfi = pfi->next;
1479 if( action == REMOVE_SUBSETS ) /* also add the superset */
1481 if( fi->fi_flags & FI_SCALABLE )
1483 fi->next = fr->fi;
1484 fr->fi = fi;
1486 else if( prev ) prev->next = fi; else fr->fi = fi;
1487 fr->count++;
1490 #ifdef DEBUG_FONT_INIT
1491 if( i ) dprintf_font(stddeb,"\t purged %i subsets [%i]\n", i , fr->count);
1492 #endif
1495 /***********************************************************************
1496 * XFONT_FindFIList
1498 static fontResource* XFONT_FindFIList( fontResource* pfr, const char* pTypeFace )
1500 while( pfr )
1502 if( !lstrcmpi32A( pfr->lfFaceName, pTypeFace ) ) break;
1503 pfr = pfr->next;
1505 return pfr;
1508 /***********************************************************************
1509 * XFONT_MatchDeviceFont
1511 * Scan font resource tree.
1513 static BOOL32 XFONT_MatchDeviceFont( fontResource* start, fontMatch* pfm )
1515 fontMatch fm = *pfm;
1517 pfm->pfi = NULL;
1518 if( fm.plf->lfFaceName[0] )
1520 LPSTR str = XFONT_CheckAliasTable( fm.plf->lfFaceName );
1521 fm.pfr = XFONT_FindFIList( start, str ? str : fm.plf->lfFaceName );
1524 if( fm.pfr ) /* match family */
1526 dprintf_font(stddeb, "%s\n", fm.pfr->lfFaceName );
1528 XFONT_MatchFIList( &fm );
1529 *pfm = fm;
1532 if( !pfm->pfi ) /* match all available fonts */
1534 UINT32 current_score, score = (UINT32)(-1);
1536 fm.flags |= FO_MATCH_PAF;
1537 for( start = fontList; start && score; start = start->next )
1539 fm.pfr = start;
1540 dprintf_font(stddeb, "%s\n", fm.pfr->lfFaceName );
1542 current_score = XFONT_MatchFIList( &fm );
1543 if( current_score < score )
1545 score = current_score;
1546 *pfm = fm;
1550 return TRUE;
1554 /***********************************************************************
1555 * X Font Cache
1557 static void XFONT_GrowFreeList(int start, int end)
1559 /* add all entries from 'start' up to and including 'end' */
1561 memset( fontCache + start, 0, (end - start + 1) * sizeof(fontObject) );
1563 fontCache[end].lru = fontLF;
1564 fontCache[end].count = -1;
1565 fontLF = start;
1566 while( start < end )
1568 fontCache[start].count = -1;
1569 fontCache[start].lru = start + 1;
1570 start++;
1574 static fontObject* XFONT_LookupCachedFont( LPLOGFONT16 plf, UINT16* checksum )
1576 UINT16 cs = __lfCheckSum( plf );
1577 int i = fontMRU, prev = -1;
1579 *checksum = cs;
1580 while( i >= 0 )
1582 if( fontCache[i].lfchecksum == cs &&
1583 !(fontCache[i].fo_flags & FO_REMOVED) )
1585 /* FIXME: something more intelligent here */
1587 if( !memcmp( plf, &fontCache[i].lf,
1588 sizeof(LOGFONT16) - LF_FACESIZE ) &&
1589 !lstrncmpi32A( plf->lfFaceName, fontCache[i].lf.lfFaceName,
1590 LF_FACESIZE ) )
1592 /* remove temporarily from the lru list */
1594 if( prev >= 0 )
1595 fontCache[prev].lru = fontCache[i].lru;
1596 else
1597 fontMRU = (INT16)fontCache[i].lru;
1598 return (fontCache + i);
1601 prev = i;
1602 i = (INT16)fontCache[i].lru;
1604 return NULL;
1607 static fontObject* XFONT_GetCacheEntry()
1609 int i;
1611 if( fontLF == -1 )
1613 int prev_i, prev_j, j;
1615 dprintf_font(stddeb,"font cache is full\n");
1617 /* lookup the least recently used font */
1619 for( prev_i = prev_j = j = -1, i = fontMRU; i >= 0; i = (INT16)fontCache[i].lru )
1621 if( fontCache[i].count <= 0 &&
1622 !(fontCache[i].fo_flags & FO_SYSTEM) )
1624 prev_j = prev_i;
1625 j = i;
1627 prev_i = i;
1630 if( j >= 0 ) /* unload font */
1632 /* detach from the lru list */
1634 dprintf_font(stddeb,"\tfreeing entry %i\n", j );
1636 if( prev_j >= 0 )
1637 fontCache[prev_j].lru = fontCache[j].lru;
1638 else fontMRU = (INT16)fontCache[j].lru;
1640 /* FIXME: lpXForm, lpPixmap */
1641 XFreeFont( display, fontCache[j].fs );
1643 memset( fontCache + j, 0, sizeof(fontObject) );
1644 return (fontCache + j);
1646 else /* expand cache */
1648 fontObject* newCache;
1650 prev_i = fontCacheSize + FONTCACHE;
1652 dprintf_font(stddeb,"\tgrowing font cache from %i to %i\n", fontCacheSize, prev_i );
1654 if( (newCache = (fontObject*)HeapReAlloc(SystemHeap, 0,
1655 fontCache, prev_i)) )
1657 i = fontCacheSize;
1658 fontCacheSize = prev_i;
1659 fontCache = newCache;
1660 XFONT_GrowFreeList( i, fontCacheSize - 1);
1662 else return NULL;
1666 /* detach from the free list */
1668 i = fontLF;
1669 fontLF = (INT16)fontCache[i].lru;
1670 fontCache[i].count = 0;
1671 return (fontCache + i);
1674 static int XFONT_ReleaseCacheEntry(fontObject* pfo)
1676 UINT32 u = (UINT32)(pfo - fontCache);
1678 if( u < fontCacheSize ) return (--fontCache[u].count);
1679 return -1;
1682 /***********************************************************************
1683 * X Device Font Objects
1685 static X_PHYSFONT XFONT_RealizeFont( LPLOGFONT16 plf )
1687 UINT16 checksum;
1688 fontObject* pfo = XFONT_LookupCachedFont( plf, &checksum );
1690 if( !pfo )
1692 fontMatch fm = { NULL, NULL, 0, 0, plf};
1693 INT32 i, index;
1695 if( XTextCaps & TC_SF_X_YINDEP ) fm.flags = FO_MATCH_XYINDEP;
1697 /* allocate new font cache entry */
1699 if( (pfo = XFONT_GetCacheEntry()) )
1701 LPSTR lpLFD = HeapAlloc( GetProcessHeap(), 0, MAX_LFD_LENGTH );
1703 if( lpLFD ) /* initialize entry and load font */
1705 UINT32 uRelaxLevel = 0;
1707 dprintf_font(stddeb,"XRealizeFont: (%u) '%s' h=%i weight=%i %s\n",
1708 plf->lfCharSet, plf->lfFaceName, plf->lfHeight,
1709 plf->lfWeight, (plf->lfItalic) ? "Italic" : "" );
1711 XFONT_MatchDeviceFont( fontList, &fm );
1713 pfo->fr = fm.pfr;
1714 pfo->fi = fm.pfi;
1715 pfo->fo_flags = fm.flags & ~FO_MATCH_MASK;
1717 memcpy( &pfo->lf, plf, sizeof(LOGFONT16) );
1718 pfo->lfchecksum = checksum;
1722 LFD_ComposeLFD( pfo, fm.height, lpLFD, uRelaxLevel++ );
1723 if( (pfo->fs = XLoadQueryFont( display, lpLFD )) ) break;
1724 } while( uRelaxLevel );
1726 if( XFONT_GetLeading( &pfo->fi->df, pfo->fs, &i, NULL ) )
1727 pfo->foAvgCharWidth = (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].width;
1728 else
1729 pfo->foAvgCharWidth = (INT16)XFONT_GetAvgCharWidth( &pfo->fi->df, pfo->fs );
1730 pfo->foInternalLeading = (INT16)i;
1732 /* FIXME: If we've got a soft font or
1733 * there are FO_SYNTH_... flags for the
1734 * non PROOF_QUALITY request, the engine
1735 * should rasterize characters into mono
1736 * pixmaps and store them in the pfo->lpPixmap
1737 * array (pfo->fs should be updated as well).
1738 * X11DRV_ExtTextOut() must be heavily modified
1739 * to support pixmap blitting and FO_SYNTH_...
1740 * styles.
1743 pfo->lpXForm = NULL;
1744 pfo->lpPixmap = NULL;
1746 HeapFree( GetProcessHeap(), 0, lpLFD );
1748 else /* attach back to the free list */
1750 pfo->count = -1;
1751 pfo->lru = fontLF;
1752 fontLF = (pfo - fontCache);
1753 pfo = NULL;
1757 if( !pfo ) /* couldn't get a new entry, get one of the cached fonts */
1759 UINT32 current_score, score = (UINT32)(-1);
1761 i = index = fontMRU;
1762 fm.flags |= FO_MATCH_PAF;
1765 pfo = fontCache + i;
1766 fm.pfr = pfo->fr; fm.pfi = pfo->fi;
1768 current_score = XFONT_Match( &fm );
1769 if( current_score < score ) index = i;
1771 i = pfo->lru;
1772 } while( i >= 0 );
1773 pfo = fontCache + index;
1774 pfo->count++;
1775 return (X_PHYSFONT)(X_PFONT_MAGIC | index);
1779 /* attach at the head of the lru list */
1781 pfo->count++;
1782 pfo->lru = fontMRU;
1783 fontMRU = (pfo - fontCache);
1785 dprintf_font(stddeb,"physfont %i\n", fontMRU);
1787 return (X_PHYSFONT)(X_PFONT_MAGIC | fontMRU);
1790 /***********************************************************************
1791 * XFONT_GetFontObject
1793 fontObject* XFONT_GetFontObject( X_PHYSFONT pFont )
1795 if( CHECK_PFONT(pFont) ) return __PFONT(pFont);
1796 return NULL;
1799 /***********************************************************************
1800 * XFONT_GetFontStruct
1802 XFontStruct* XFONT_GetFontStruct( X_PHYSFONT pFont )
1804 if( CHECK_PFONT(pFont) ) return __PFONT(pFont)->fs;
1805 return NULL;
1808 /***********************************************************************
1809 * XFONT_GetFontInfo
1811 LPIFONTINFO16 XFONT_GetFontInfo( X_PHYSFONT pFont )
1813 if( CHECK_PFONT(pFont) ) return &(__PFONT(pFont)->fi->df);
1814 return NULL;
1819 /* X11DRV Interface ****************************************************
1821 * Exposed via the dc->funcs dispatch table. *
1823 ***********************************************************************/
1824 /***********************************************************************
1825 * X11DRV_FONT_SelectObject
1827 HFONT32 X11DRV_FONT_SelectObject( DC* dc, HFONT32 hfont, FONTOBJ* font )
1829 HFONT32 hPrevFont = 0;
1831 if( CHECK_PFONT(dc->u.x.font) )
1832 XFONT_ReleaseCacheEntry( __PFONT(dc->u.x.font) );
1834 dc->u.x.font = XFONT_RealizeFont( &font->logfont );
1835 hPrevFont = dc->w.hFont;
1836 dc->w.hFont = hfont;
1838 return hPrevFont;
1842 /***********************************************************************
1844 * X11DRV_EnumDeviceFonts
1846 BOOL32 X11DRV_EnumDeviceFonts( DC* dc, LPLOGFONT16 plf,
1847 DEVICEFONTENUMPROC proc, LPARAM lp )
1849 ENUMLOGFONTEX16 lf;
1850 NEWTEXTMETRIC16 tm;
1851 fontResource* pfr = fontList;
1852 BOOL32 b, bRet = 0;
1854 if( plf->lfFaceName[0] )
1856 pfr = XFONT_FindFIList( pfr, plf->lfFaceName );
1857 if( pfr )
1859 fontInfo* pfi;
1860 for( pfi = pfr->fi; pfi; pfi = pfi->next )
1861 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
1862 XFONT_GetFontMetric( pfi, &lf, &tm ), lp )) )
1863 bRet = b;
1864 else break;
1867 else
1868 for( ; pfr ; pfr = pfr->next )
1869 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
1870 XFONT_GetFontMetric( pfr->fi, &lf, &tm ), lp )) )
1871 bRet = b;
1872 else break;
1874 return bRet;
1878 /***********************************************************************
1879 * X11DRV_GetTextExtentPoint
1881 BOOL32 X11DRV_GetTextExtentPoint( DC *dc, LPCSTR str, INT32 count,
1882 LPSIZE32 size )
1884 XFontStruct* pfs = XFONT_GetFontStruct( dc->u.x.font );
1885 if( pfs )
1887 int dir, ascent, descent;
1888 XCharStruct info;
1890 XTextExtents( pfs, str, count, &dir, &ascent, &descent, &info );
1891 size->cx = abs((info.width + dc->w.breakRem + count * dc->w.charExtra)
1892 * dc->wndExtX / dc->vportExtX);
1893 size->cy = abs((pfs->ascent + pfs->descent) * dc->wndExtY / dc->vportExtY);
1894 return TRUE;
1896 return FALSE;
1900 /***********************************************************************
1901 * X11DRV_GetTextMetrics
1903 BOOL32 X11DRV_GetTextMetrics(DC *dc, TEXTMETRIC32A *metrics)
1905 if( CHECK_PFONT(dc->u.x.font) )
1907 fontObject* pfo = __PFONT(dc->u.x.font);
1908 XFONT_GetTextMetric( pfo, metrics );
1909 return TRUE;
1911 return FALSE;
1915 /***********************************************************************
1916 * X11DRV_GetCharWidth
1918 BOOL32 X11DRV_GetCharWidth( DC *dc, UINT32 firstChar, UINT32 lastChar,
1919 LPINT32 buffer )
1921 XFontStruct* xfs = XFONT_GetFontStruct( dc->u.x.font );
1923 if( xfs )
1925 int i;
1927 if (xfs->per_char == NULL)
1928 for (i = firstChar; i <= lastChar; i++)
1929 *buffer++ = xfs->min_bounds.width;
1930 else
1932 XCharStruct *cs, *def;
1933 static XCharStruct __null_char = { 0, 0, 0, 0, 0, 0 };
1935 CI_GET_CHAR_INFO(xfs, xfs->default_char, &__null_char, def);
1937 for (i = firstChar; i <= lastChar; i++)
1939 if (i >= xfs->min_char_or_byte2 && i <= xfs->max_char_or_byte2)
1941 cs = &xfs->per_char[(i - xfs->min_char_or_byte2)];
1942 if (CI_NONEXISTCHAR(cs)) cs = def;
1943 } else cs = def;
1944 *buffer++ = MAX(cs->width, 0 );
1947 return TRUE;
1949 return FALSE;
1952 /***********************************************************************
1954 * Font Resource API *
1956 ***********************************************************************/
1957 /***********************************************************************
1958 * AddFontResource16 (GDI.119)
1960 * Can be either .FON, or .FNT, or .TTF, or .FOT font file.
1962 * FIXME: Load header and find the best-matching font in the fontList;
1963 * fixup dfPoints if all metrics are identical, otherwise create
1964 * new fontAlias. When soft font support is ready this will
1965 * simply create a new fontResource ('filename' will go into
1966 * the pfr->resource field) with FR_SOFTFONT/FR_SOFTRESOURCE
1967 * flag set.
1969 INT16 AddFontResource16( LPCSTR filename )
1971 return AddFontResource32A( filename );
1975 /***********************************************************************
1976 * AddFontResource32A (GDI32.2)
1978 INT32 AddFontResource32A( LPCSTR str )
1980 if (HIWORD(str)) /* font file */
1981 fprintf( stdnimp, "STUB: AddFontResource('%s')\n", str );
1982 else /* font resource handle */
1983 fprintf( stdnimp, "STUB: AddFontResource(%04x)\n", LOWORD(str) );
1984 return 1;
1988 /***********************************************************************
1989 * AddFontResource32W (GDI32.4)
1991 INT32 AddFontResource32W( LPCWSTR str )
1993 fprintf( stdnimp, "STUB: AddFontResource32W(%p)\n", str );
1994 return 1;
1997 /***********************************************************************
1998 * RemoveFontResource16 (GDI.136)
2000 BOOL16 RemoveFontResource16( SEGPTR str )
2002 if (HIWORD(str))
2003 fprintf( stdnimp, "STUB: RemoveFontResource('%s')\n",
2004 (char *)PTR_SEG_TO_LIN( str) );
2005 else
2006 fprintf( stdnimp, "STUB: RemoveFontResource(%04x)\n", LOWORD(str) );
2007 return TRUE;
2011 /***********************************************************************
2012 * RemoveFontResource32A (GDI32.284)
2014 BOOL32 RemoveFontResource32A( LPCSTR str )
2016 if (HIWORD(str))
2017 fprintf( stdnimp, "STUB: RemoveFontResource('%s')\n", str );
2018 else
2019 fprintf( stdnimp, "STUB: RemoveFontResource(%04x)\n", LOWORD(str) );
2020 return TRUE;
2024 /***********************************************************************
2025 * RemoveFontResource32W (GDI32.286)
2027 BOOL32 RemoveFontResource32W( LPCWSTR str )
2029 fprintf( stdnimp, "STUB: RemoveFontResource32W(%p)\n", str );
2030 return TRUE;