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).
16 #include <sys/types.h>
20 #include <X11/Xatom.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
48 struct __fontAlias* next;
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) \
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; \
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 /***********************************************************************
114 static UINT16 __lfCheckSum( LPLOGFONT16 plf )
116 CHAR font[LF_FACESIZE];
120 #define ptr ((UINT16*)plf)
121 for( i = 0; i < 9; i++ ) checksum ^= *ptr++;
124 #define ptr ((CHAR*)plf)
125 do { font[i++] = tolower(*ptr); } while (*ptr++);
126 for( ptr = font, i >>= 1; i > 0; i-- )
128 #define ptr ((UINT16*)plf)
134 static UINT16 __genericCheckSum( UINT16* ptr, int size )
139 for( i = 0, size >>= 1; i < size; i++ ) checksum ^= *ptr++;
143 /*************************************************************************
144 * LFD parse/compose routines
146 static char* LFD_Advance(LPSTR lpFont, UINT16 uParmsNo)
151 for( ; j < uParmsNo && *lpch; lpch++ ) if( *lpch == LFDSeparator[1] ) j++;
155 static void LFD_GetWeight( fontInfo* fi, LPSTR lpStr, int j)
157 if( j == 1 && *lpStr == '0' )
158 fi->fi_flags |= FI_POLYWEIGHT;
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;
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;
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)
194 switch( tolower( *lpStr ) )
196 case '0': fi->fi_flags |= FI_POLYSLANT; /* haven't seen this one yet */
198 case 'r': fi->df.dfItalic = 0;
201 fi->fi_flags |= FI_OBLIQUE;
202 case 'i': fi->df.dfItalic = 1;
210 /*************************************************************************
213 * Fill in some fields in the fontInfo struct.
215 static int LFD_InitFontInfo( fontInfo* fi, LPSTR lpstr )
218 int i, j, dec_style_check, scalability;
221 memset(fi, 0, sizeof(fontInfo) );
224 lpch = LFD_Advance( lpstr, 1);
225 if( !*lpch ) return FALSE;
226 j = lpch - lpstr - 1;
227 LFD_GetWeight( fi, lpstr, j );
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 );
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;
241 fi->fi_flags |= FI_NORMAL;
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" */
252 if( strstr(lpstr, "sans") )
254 fi->df.dfPitchAndFamily |= FF_SWISS;
257 if( strstr(lpstr, "script") )
259 fi->df.dfPitchAndFamily |= FF_SCRIPT;
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 */
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);
296 case '\0': return FALSE;
298 case 'p': fi->fi_flags |= FI_VARIABLEPITCH;
300 case 'c': fi->df.dfPitchAndFamily |= FF_MODERN;
301 fi->fi_flags |= FI_FIXEDEX;
303 case 'm': fi->fi_flags |= FI_FIXEDPITCH;
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 */
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;
340 fi->df.dfCharSet = OEM_CHARSET; /* FIXME: -cp126-.. from fnt2bdf */
345 /*************************************************************************
348 static BOOL32 LFD_ComposeLFD( fontObject* fo,
349 INT32 height, LPSTR lpLFD, UINT32 uRelax )
351 int h, w, ch, point = 0;
353 const char* lpEncoding = NULL;
355 lstrcpy32A( lpLFD, fo->fr->resource );
358 switch( fo->fi->df.dfWeight )
361 strcat( lpLFD, "bold" ); break;
363 if( fo->fi->fi_flags & FI_FW_BOOK )
364 strcat( lpLFD, "book" );
366 strcat( lpLFD, "medium" );
369 strcat( lpLFD, "demi" );
370 if( !( fo->fi->fi_flags & FI_FW_DEMI) )
371 strcat ( lpLFD, "bold" );
374 strcat( lpLFD, "black" ); break;
376 strcat( lpLFD, "light" ); break;
378 strcat( lpLFD, "*" );
382 if( fo->fi->df.dfItalic )
383 if( fo->fi->fi_flags & FI_OBLIQUE )
384 strcat( lpLFD, "-o" );
386 strcat( lpLFD, "-i" );
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-*-");
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';
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];
430 /* RealizeFont() will call us repeatedly with increasing uRelax
431 * until XLoadFont() succeeds. */
436 sprintf( lpch, "%i-%i-%i-%c-%c-*-%s*", h, point,
437 fo->fi->lfd_resolution, ch, w, lpEncoding );
443 sprintf( lpch, "%i-*-%i-%c-%c-*-%s*", h,
444 fo->fi->lfd_resolution, ch, w, lpEncoding );
448 sprintf( lpch, "%i-*-%i-%c-*-*-%s*",
449 h, fo->fi->lfd_resolution, ch, lpEncoding );
453 sprintf( lpch, "%i-*-%i-%c-*-*-%s*", fo->fi->lfd_height,
454 fo->fi->lfd_resolution, ch, lpEncoding );
458 sprintf( lpch, "%i-*-*-*-*-*-%s*", fo->fi->lfd_height, lpEncoding );
461 dprintf_font(stddeb,"\tLFD: %s\n", lpLFD );
466 /***********************************************************************
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 );
480 if( XGetFontProperty(x_fs, XA_CAP_HEIGHT, &height) == False )
484 height = x_fs->per_char['X' - min].ascent;
486 if (x_fs->ascent >= x_fs->max_bounds.ascent)
487 height = x_fs->max_bounds.ascent;
490 height = x_fs->ascent;
492 *pEL = x_fs->max_bounds.ascent - height;
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;
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;
516 return (width / chars);
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)
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;
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;
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;
591 if( pfo->fo_flags & FO_SYNTH_ITALIC )
593 pTM->tmOverhang += pTM->tmHeight/3;
596 pTM->tmItalic = pdf->dfItalic;
598 pTM->tmWeight = pdf->dfWeight;
599 if( pfo->fo_flags & FO_SYNTH_BOLD )
602 pTM->tmWeight += 100;
605 *(INT32*)&pTM->tmFirstChar = *(INT32*)&pdf->dfFirstChar;
607 pTM->tmCharSet = pdf->dfCharSet;
608 pTM->tmPitchAndFamily = pdf->dfPitchAndFamily;
609 pTM->tmDigitizedAspectX = pdf->dfHorizRes;
610 pTM->tmDigitizedAspectY = pdf->dfVertRes;
613 /***********************************************************************
614 * XFONT_GetFontMetric
616 * Retrieve font metric info (enumeration).
618 static UINT32 XFONT_GetFontMetric( fontInfo* pfi, LPENUMLOGFONTEX16 pLF,
619 LPNEWTEXTMETRIC16 pTM )
621 memset( pLF, 0, sizeof(*pLF) );
622 memset( pTM, 0, sizeof(*pTM) );
624 #define plf ((LPLOGFONT16)pLF)
625 plf->lfHeight = pTM->tmHeight = pfi->df.dfPixHeight;
626 plf->lfWidth = pTM->tmAveCharWidth = pfi->df.dfAvgWidth;
627 plf->lfWeight = pTM->tmWeight = pfi->df.dfWeight;
628 plf->lfItalic = pTM->tmItalic = pfi->df.dfItalic;
629 plf->lfUnderline = pTM->tmUnderlined = pfi->df.dfUnderline;
630 plf->lfStrikeOut = pTM->tmStruckOut = pfi->df.dfStrikeOut;
631 plf->lfCharSet = pTM->tmCharSet = pfi->df.dfCharSet;
633 /* convert pitch values */
635 pTM->tmPitchAndFamily = pfi->df.dfPitchAndFamily;
636 plf->lfPitchAndFamily = (pfi->df.dfPitchAndFamily & 0xF1) + 1;
638 lstrcpyn32A( plf->lfFaceName, pfi->df.dfFace, LF_FACESIZE );
641 pTM->tmAscent = pfi->df.dfAscent;
642 pTM->tmDescent = pTM->tmHeight - pTM->tmAscent;
643 pTM->tmInternalLeading = pfi->df.dfInternalLeading;
644 pTM->tmMaxCharWidth = pfi->df.dfMaxWidth;
645 pTM->tmDigitizedAspectX = pfi->df.dfHorizRes;
646 pTM->tmDigitizedAspectY = pfi->df.dfVertRes;
648 *(INT32*)&pTM->tmFirstChar = *(INT32*)&pfi->df.dfFirstChar;
650 /* return font type */
652 return pfi->df.dfType;
656 /***********************************************************************
659 * dfPitchAndFamily flags for some common typefaces.
661 static BYTE XFONT_FixupFlags( LPCSTR lfFaceName )
663 switch( lfFaceName[0] )
666 case 'H': if(!lstrcmpi32A(lfFaceName, "Helvetica") )
670 case 'C': if(!lstrcmpi32A(lfFaceName, "Courier") )
674 case 'P': if( !lstrcmpi32A(lfFaceName,"Palatino") )
678 case 'T': if(!lstrncmpi32A(lfFaceName, "Times", 5) )
682 case 'U': if(!lstrcmpi32A(lfFaceName, "Utopia") )
686 case 'Z': if(!lstrcmpi32A(lfFaceName, "Zapf Dingbats") )
687 return FF_DECORATIVE;
693 /***********************************************************************
696 * Build generic Windows aliases for X font names.
698 * -misc-fixed- -> "Fixed"
699 * -sony-fixed- -> "Sony Fixed", etc...
701 static void XFONT_WindowsNames( char* buffer )
703 fontResource* fr, *pfr;
708 for( fr = fontList; fr ; fr = fr->next )
710 if( fr->fr_flags & FR_NAMESET ) continue; /* skip already assigned */
712 lpstr = LFD_Advance(fr->resource, 2);
713 i = lpstr - LFD_Advance( lpstr, 1 );
715 for( pfr = fontList; pfr != fr ; pfr = pfr->next )
716 if( pfr->fr_flags & FR_NAMESET )
718 lpch = LFD_Advance(pfr->resource, 2);
720 /* check if already have the same face name */
722 if( !lstrncmp32A(lpch, lpstr, i) ) break;
724 if( pfr != fr ) /* prepend vendor name */
725 lpstr = fr->resource + 1;
727 for( i = 0, up = 1, lpch = fr->lfFaceName; *lpstr && i < 32;
728 lpch++, lpstr++, i++ )
730 if( *lpstr == LFDSeparator[1] || *lpstr == ' ' )
735 else if( isalpha(*lpstr) && up )
737 *lpch = toupper(*lpstr);
742 while (*(lpch - 1) == ' ') *(--lpch) = '\0';
744 if( (bFamilyStyle = XFONT_FixupFlags( fr->lfFaceName )) )
747 for( fi = fr->fi ; fi ; fi = fi->next )
748 fi->df.dfPitchAndFamily |= bFamilyStyle;
751 #ifdef DEBUG_FONT_INIT
752 dprintf_font(stddeb,"typeface \'%s\'\n", fr->lfFaceName);
754 fr->fr_flags |= FR_NAMESET;
757 if( PROFILE_GetWineIniString( INIFontSection, INIDefault, "", buffer, 128 ) )
759 while( *buffer && isspace(*buffer) ) buffer++;
760 for( fr = NULL, pfr = fontList; pfr; pfr = pfr->next )
762 i = lstrlen32A( pfr->resource );
763 if( !lstrncmpi32A( pfr->resource, buffer, i) )
767 fr->next = pfr->next;
768 pfr->next = fontList;
778 /***********************************************************************
781 static fontAlias* XFONT_CreateAlias( LPCSTR lpTypeFace, LPCSTR lpAlias )
783 fontAlias* pfa = aliasTable;
784 int j = lstrlen32A(lpTypeFace) + 1;
786 while( pfa->next ) pfa = pfa->next;
787 pfa->next = HeapAlloc( SystemHeap, 0, sizeof(fontAlias) +
788 j + lstrlen32A(lpAlias) + 1 );
789 if((pfa = pfa->next))
792 pfa->faTypeFace = (LPSTR)(pfa + 1);
793 lstrcpy32A( pfa->faTypeFace, lpTypeFace );
794 pfa->faAlias = pfa->faTypeFace + j;
795 lstrcpy32A( pfa->faAlias, lpAlias );
797 #ifdef DEBUG_FONT_INIT
798 dprintf_font(stddeb, "\tadded alias '%s' for %s\n", lpAlias, lpTypeFace );
805 /***********************************************************************
808 * Read user-defined aliases from wine.conf. Format is as follows
810 * Alias# = [Windows font name],[LFD font name], <substitute original name>
813 * Alias0 = Arial, -adobe-helvetica-
814 * Alias1 = Times New Roman, -bitstream-courier-, 1
817 static void XFONT_LoadAliases( char** buffer, int buf_size )
823 *buffer = HeapReAlloc(SystemHeap, 0, *buffer, 256 );
826 wsprintf32A( subsection, "%s%i", INISubSection, i++ );
828 if( PROFILE_GetWineIniString( INIFontSection, subsection, "", *buffer, 128 ) )
830 char* lpchX, *lpchW = *buffer;
832 while( isspace(*lpchW) ) lpchW++;
833 lpchX = PROFILE_GetStringItem( lpchW );
839 for (fr = fontList; fr ; fr = fr->next)
843 j = lstrlen32A( fr->resource );
845 if( !lstrncmpi32A( fr->resource, lpchX, j) )
847 char* lpch = PROFILE_GetStringItem( lpchX );
851 #ifdef DEBUG_FONT_INIT
852 dprintf_font(stddeb, "\tsubstituted '%s' with %s\n",
853 fr->lfFaceName, lpchW );
855 lstrcpyn32A( fr->lfFaceName, lpchW, LF_FACESIZE );
856 fr->fr_flags |= FR_NAMESET;
860 /* create new entry in the alias table */
861 XFONT_CreateAlias(fr->lfFaceName, lpchW);
867 else fprintf(stderr, "XFONT_Init: malformed font alias '%s'\n", *buffer );
873 /***********************************************************************
874 * XFONT_UserMetricsCache
876 * Returns expanded name for the ~/.wine/.cachedmetrics file.
878 static char* XFONT_UserMetricsCache( char* buffer, int* buf_size )
882 pwd = getpwuid(getuid());
883 if( pwd && pwd->pw_dir )
885 int i = lstrlen32A( pwd->pw_dir ) + lstrlen32A( INIWinePrefix ) + lstrlen32A( INIFontMetrics ) + 2;
886 if( i > *buf_size ) buffer = (char*) HeapReAlloc( SystemHeap, 0, buffer, *buf_size = i );
887 lstrcpy32A( buffer, pwd->pw_dir );
888 strcat( buffer, INIWinePrefix );
889 strcat( buffer, INIFontMetrics );
890 } else buffer[0] = '\0';
895 /***********************************************************************
896 * XFONT_ReadCachedMetrics
898 static BOOL32 XFONT_ReadCachedMetrics( int fd, unsigned x_checksum, int x_count )
906 read( fd, &u, sizeof(unsigned) );
907 read( fd, &i, sizeof(int) );
909 if( u == x_checksum && i == x_count )
911 off_t length, offset = 3 * sizeof(int);
913 /* read total size */
914 read( fd, &i, sizeof(int) );
915 length = lseek( fd, 0, SEEK_END );
917 if( length == (i + offset) )
919 lseek( fd, offset, SEEK_SET );
920 fontList = (fontResource*)HeapAlloc( SystemHeap, 0, i);
923 fontResource* pfr = fontList;
924 fontInfo* pfi = NULL;
926 dprintf_font(stddeb,"Reading cached font metrics:\n");
928 read( fd, fontList, i); /* read all metrics at once */
929 while( offset < length )
931 offset += sizeof(fontResource) + sizeof(fontInfo);
932 pfr->fi = pfi = (fontInfo*)(pfr + 1);
936 if( offset > length ||
937 (int)(pfi->next) != j++ ) goto fail;
939 pfi->df.dfFace = pfr->lfFaceName;
942 if( j > pfr->count ) break;
945 offset += sizeof(fontInfo);
950 pfr->next = (fontResource*)(pfi + 1);
955 if( pfr->next == NULL &&
956 *(int*)(pfi + 1) == X_FMC_MAGIC )
959 char* lpch = (char*)((int*)(pfi + 1) + 1);
960 offset += sizeof(int);
961 for( pfr = fontList; pfr; pfr = pfr->next )
963 dprintf_font(stddeb,"\t%s, %i instances\n", lpch, pfr->count );
964 pfr->resource = lpch;
967 if( ++offset > length ) goto fail;
968 if( !*lpch++ ) break;
978 if( fontList ) HeapFree( SystemHeap, 0, fontList );
985 /***********************************************************************
986 * XFONT_WriteCachedMetrics
988 static BOOL32 XFONT_WriteCachedMetrics( int fd, unsigned x_checksum, int x_count, int n_ff )
997 /* font metrics file:
1001 * +0008 total size to load
1002 * +000C prepackaged font metrics
1005 * +...x + 4 LFD stubs
1008 write( fd, &x_checksum, sizeof(unsigned) );
1009 write( fd, &x_count, sizeof(int) );
1011 for( j = i = 0, pfr = fontList; pfr; pfr = pfr->next )
1013 i += lstrlen32A( pfr->resource ) + 1;
1016 i += n_ff * sizeof(fontResource) + j * sizeof(fontInfo) + sizeof(int);
1017 write( fd, &i, sizeof(int) );
1019 dprintf_font(stddeb,"Writing font cache:\n");
1021 for( pfr = fontList; pfr; pfr = pfr->next )
1025 dprintf_font(stddeb,"\t%s, %i instances\n", pfr->resource, pfr->count );
1027 i = write( fd, pfr, sizeof(fontResource) );
1028 if( i == sizeof(fontResource) )
1030 for( k = 1, pfi = pfr->fi; pfi; pfi = pfi->next )
1032 memcpy( &fi, pfi, sizeof(fi) );
1034 fi.df.dfFace = NULL;
1035 fi.next = (fontInfo*)k; /* loader checks this */
1037 j = write( fd, &fi, sizeof(fi) );
1040 if( j == sizeof(fontInfo) ) continue;
1044 if( i == sizeof(fontResource) && j == sizeof(fontInfo) )
1046 i = j = X_FMC_MAGIC;
1047 write( fd, &i, sizeof(int) );
1048 for( pfr = fontList; pfr && i == j; pfr = pfr->next )
1050 i = lstrlen32A( pfr->resource ) + 1;
1051 j = write( fd, pfr->resource, i );
1060 /***********************************************************************
1063 * Initialize font resource list and allocate font cache.
1065 BOOL32 X11DRV_FONT_Init( DeviceCaps* pDevCaps )
1068 fontResource* fr, *pfr;
1070 unsigned x_checksum;
1071 int i, j, k, x_count, fd = -1, buf_size = 0;
1072 char* lpstr, *lpch, *lpmetrics, *buffer;
1075 DefResolution = PROFILE_GetWineIniInt( INIFontSection, "Resolution", 0 );
1076 if( !DefResolution ) DefResolution = pDevCaps->logPixelsY;
1078 i = abs(DefResolution - 72);
1079 j = abs(DefResolution - 75);
1080 k = abs(DefResolution - 100);
1082 if( i < j ) DefResolution = ( i < k ) ? 72 : 100;
1083 else DefResolution = ( j < k ) ? 75 : 100;
1085 x_pattern = XListFonts(display, "*", MAX_FONT_FAMILIES * 16, &x_count );
1087 dprintf_font(stddeb,"Font Mapper: initializing %i fonts [LPY=%i, DR=%i]\n",
1088 x_count, pDevCaps->logPixelsY, DefResolution);
1089 for( i = x_checksum = 0; i < x_count; i++ )
1092 printf("%i\t: %s\n", i, x_pattern[i] );
1095 j = lstrlen32A( x_pattern[i] );
1096 if( j ) x_checksum ^= __genericCheckSum( (UINT16*)(x_pattern[i]), j );
1098 x_checksum |= X_PFONT_MAGIC;
1101 buffer = HeapAlloc( SystemHeap, 0, buf_size );
1104 /* deal with systemwide font metrics cache */
1106 if( PROFILE_GetWineIniString( INIFontSection, "FontMetrics", "", buffer, 128 ) )
1107 fd = open( buffer, O_RDONLY );
1109 if( XFONT_ReadCachedMetrics(fd, x_checksum, x_count) == FALSE )
1112 buffer = XFONT_UserMetricsCache( buffer, &buf_size );
1115 fd = open( buffer, O_RDONLY );
1116 if( XFONT_ReadCachedMetrics(fd, x_checksum, x_count) == FALSE )
1117 lpmetrics = HEAP_strdupA( SystemHeap, 0, buffer ); /* update later on */
1122 if( fontList == NULL ) /* build metrics from scratch */
1127 for( i = n_ff = 0; i < x_count; i++ )
1129 typeface = lpch = x_pattern[i];
1131 lpch = LFD_Advance(typeface, 3); /* extra '-' in the beginning */
1132 if( !*lpch ) continue;
1135 j = lpch - typeface; /* resource name length */
1137 /* find a family to insert into */
1139 for( pfr = NULL, fr = fontList; fr; fr = fr->next )
1141 if( !lstrncmpi32A(fr->resource, typeface, j) &&
1142 lstrlen32A(fr->resource) == j ) break;
1146 if( !fi ) fi = (fontInfo*) HeapAlloc(SystemHeap, 0, sizeof(fontInfo));
1148 if( !fr ) /* add new family */
1150 if( n_ff++ > MAX_FONT_FAMILIES ) break;
1152 if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1154 fr = (fontResource*) HeapAlloc(SystemHeap, 0, sizeof(fontResource));
1155 memset(fr, 0, sizeof(fontResource));
1156 fr->resource = (char*) HeapAlloc(SystemHeap, 0, j + 1 );
1157 lstrcpyn32A( fr->resource, typeface, j + 1 );
1159 #ifdef DEBUG_FONT_INIT
1160 dprintf_font(stddeb," family: %s\n", fr->resource );
1163 if( pfr ) pfr->next = fr;
1166 else if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1168 /* check if we already have something better than "fi" */
1170 for( pfi = fr->fi, j = 0; pfi && j <= 0; pfi = pfi->next )
1171 if( (j = XFONT_IsSubset( pfi, fi )) < 0 )
1172 pfi->fi_flags |= FI_SUBSET; /* superseded by "fi" */
1173 if( j > 0 ) continue;
1175 /* add new font instance "fi" to the "fr" font resource */
1177 if( fi->fi_flags & FI_SCALABLE )
1179 /* set scalable font height to 24 to get an origin for extrapolation */
1181 j = lstrlen32A(typeface); j += 0x10;
1183 buffer = (char*)HeapReAlloc( SystemHeap, 0, buffer, buf_size = j );
1185 lpch = LFD_Advance(typeface, 7);
1186 memcpy( buffer, typeface, (j = lpch - typeface) );
1187 lpch = LFD_Advance(lpch, 4);
1188 sprintf( buffer + j, "%d-%d-%d-*-%c-*-", fi->lfd_height,
1189 fi->lfd_decipoints, fi->lfd_resolution,
1190 (*lpch == '-')?'*':*lpch );
1191 lpch = LFD_Advance(lpch, 2);
1192 strcat( lpstr = buffer, lpch);
1194 else lpstr = typeface;
1196 if( (x_fs = XLoadQueryFont(display, lpstr)) )
1198 fi->df.dfHorizRes = pDevCaps->logPixelsX;
1199 fi->df.dfVertRes = pDevCaps->logPixelsY;
1201 XFONT_SetFontMetric( fi, fr, x_fs );
1202 XFreeFont( display, x_fs );
1204 #ifdef DEBUG_FONT_INIT
1205 dprintf_font(stddeb,"\t[% 2ipt] '%s'\n", fi->df.dfPoints, typeface );
1207 XFONT_CheckFIList( fr, fi, REMOVE_SUBSETS );
1208 fi = NULL; /* preventing reuse */
1212 fprintf(stderr, "FONT_Init: failed to load %s\n", lpstr );
1214 XFONT_CheckFIList( fr, fi, UNMARK_SUBSETS );
1218 if( lpmetrics ) /* update cached metrics */
1220 fd = open( lpmetrics, O_CREAT | O_TRUNC | O_RDWR, 0644 ); /* -rw-r--r-- */
1221 if( XFONT_WriteCachedMetrics( fd, x_checksum, x_count, n_ff ) == FALSE )
1222 if( fd ) remove( lpmetrics ); /* couldn't write entire file */
1223 HeapFree( SystemHeap, 0, lpmetrics );
1227 if( fi ) HeapFree(SystemHeap, 0, fi);
1228 XFreeFontNames(x_pattern);
1230 /* check if we're dealing with X11 R6 server */
1232 lstrcpy32A(buffer, "-*-*-*-*-normal-*-[12 0 0 12]-*-72-*-*-*-iso8859-1");
1233 if( (x_fs = XLoadQueryFont(display, buffer)) )
1235 XTextCaps |= TC_SF_X_YINDEP;
1236 XFreeFont(display, x_fs);
1239 XFONT_WindowsNames( buffer );
1240 XFONT_LoadAliases( &buffer, buf_size );
1241 HeapFree(SystemHeap, 0, buffer);
1244 /* fontList initialization is over, allocate X font cache */
1246 fontCache = (fontObject*) HeapAlloc(SystemHeap, 0, fontCacheSize * sizeof(fontObject));
1247 XFONT_GrowFreeList(0, fontCacheSize - 1);
1249 #ifdef DEBUG_FONT_INIT
1250 dprintf_font(stddeb,"done!\n");
1253 /* update text caps parameter */
1255 pDevCaps->textCaps = XTextCaps;
1260 /***********************************************************************
1263 * Compare two fonts (only parameters set by the XFONT_InitFontInfo()).
1265 static INT32 XFONT_IsSubset(fontInfo* match, fontInfo* fi)
1269 /* 0 - keep both, 1 - keep match, -1 - keep fi */
1271 m = (BYTE*)&fi->df.dfPixWidth - (BYTE*)&fi->df.dfItalic;
1272 if( memcmp(&match->df.dfItalic, &fi->df.dfItalic, m )) return 0;
1274 if( (!((fi->fi_flags & FI_SCALABLE) + (match->fi_flags & FI_SCALABLE))
1275 && fi->lfd_height != match->lfd_height) ||
1276 (!((fi->fi_flags & FI_POLYWEIGHT) + (match->fi_flags & FI_POLYWEIGHT))
1277 && fi->df.dfWeight != match->df.dfWeight) ) return 0;
1279 m = (int)(match->fi_flags & (FI_POLYWEIGHT | FI_SCALABLE)) -
1280 (int)(fi->fi_flags & (FI_SCALABLE | FI_POLYWEIGHT));
1282 if( m == (FI_POLYWEIGHT - FI_SCALABLE) ||
1283 m == (FI_SCALABLE - FI_POLYWEIGHT) ) return 0; /* keep both */
1284 else if( m >= 0 ) return 1; /* 'match' is better */
1286 return -1; /* 'fi' is better */
1289 /***********************************************************************
1292 * Compute the matching score between the logical font and the device font.
1294 * contributions from highest to lowest:
1298 * family flags (only when the facename is not present)
1300 * weight, italics, underlines, strikeouts
1302 * NOTE: you can experiment with different penalty weights to see what happens.
1303 * http://premium.microsoft.com/msdn/library/techart/f30/f34/f40/d4d/sa8bf.htm
1305 static UINT32 XFONT_Match( fontMatch* pfm )
1307 fontInfo* pfi = pfm->pfi; /* device font to match */
1308 LPLOGFONT16 plf = pfm->plf; /* wanted logical font */
1310 BOOL32 bR6 = pfm->flags & FO_MATCH_XYINDEP; /* from TextCaps */
1311 BOOL32 bScale = pfi->fi_flags & FI_SCALABLE;
1314 dprintf_font( stddeb,"\t[ %-2ipt h=%-3i w=%-3i %s%s]", pfi->df.dfPoints,
1315 pfi->df.dfPixHeight, pfi->df.dfAvgWidth,
1316 (pfi->df.dfWeight > 400) ? "Bold " : "Normal ",
1317 (pfi->df.dfItalic) ? "Italic" : "" );
1321 if( plf->lfCharSet != DEFAULT_CHARSET &&
1322 plf->lfCharSet != pfi->df.dfCharSet ) penalty += 0x200;
1324 /* TMPF_FIXED_PITCH means exactly the opposite */
1326 if( plf->lfPitchAndFamily & FIXED_PITCH )
1328 if( pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH ) penalty += 0x100;
1330 else if( !(pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH) ) penalty += 0x2;
1332 if( plf->lfHeight > 0 )
1333 d = (h = pfi->df.dfPixHeight) - plf->lfHeight;
1334 else if( plf->lfHeight < -1 )
1335 d = (h = pfi->df.dfPoints) + plf->lfHeight;
1338 if( d && plf->lfHeight )
1340 UINT16 height = ( plf->lfHeight > 0 ) ? plf->lfHeight
1341 : ((-plf->lfHeight * pfi->df.dfPixHeight) / h);
1342 if( bScale ) pfm->height = height;
1343 else if( (plf->lfQuality != PROOF_QUALITY) && bR6 )
1345 if( d > 0 ) /* do not shrink raster fonts */
1347 pfm->height = pfi->df.dfPixHeight;
1348 penalty += (pfi->df.dfPixHeight - height) * 0x4;
1350 else /* expand only in integer multiples */
1352 pfm->height = height - height%pfi->df.dfPixHeight;
1353 penalty += (height - pfm->height) * pfm->height / height;
1356 else /* can't be scaled at all */
1358 if( plf->lfQuality != PROOF_QUALITY) pfm->flags |= FO_SYNTH_HEIGHT;
1359 pfm->height = pfi->df.dfPixHeight;
1360 penalty += (d > 0)? d * 0x8 : -d * 0x10;
1362 } else pfm->height = pfi->df.dfPixHeight;
1364 if((pfm->flags & FO_MATCH_PAF) &&
1365 (plf->lfPitchAndFamily & FF_FAMILY) != (pfi->df.dfPitchAndFamily & FF_FAMILY) )
1370 if( bR6 && bScale ) h = 0;
1373 /* FIXME: not complete */
1375 pfm->flags |= FO_SYNTH_WIDTH;
1376 h = abs(plf->lfWidth - (pfm->height * pfi->df.dfAvgWidth)/pfi->df.dfPixHeight);
1378 penalty += h * ( d ) ? 0x2 : 0x1 ;
1380 else if( !(pfi->fi_flags & FI_NORMAL) ) penalty++;
1382 if( pfi->lfd_resolution != DefResolution ) penalty++;
1384 if( plf->lfWeight != FW_DONTCARE )
1386 penalty += abs(plf->lfWeight - pfi->df.dfWeight) / 40;
1387 if( plf->lfWeight > pfi->df.dfWeight ) pfm->flags |= FO_SYNTH_BOLD;
1388 } else if( pfi->df.dfWeight >= FW_BOLD ) penalty++; /* choose normal by default */
1390 if( plf->lfItalic != pfi->df.dfItalic )
1393 pfm->flags |= FO_SYNTH_ITALIC;
1396 if( plf->lfUnderline ) pfm->flags |= FO_SYNTH_UNDERLINE;
1397 if( plf->lfStrikeOut ) pfm->flags |= FO_SYNTH_STRIKEOUT;
1399 dprintf_font(stddeb,"-> %i\n", penalty );
1404 /***********************************************************************
1407 * Scan a particular font resource for the best match.
1409 static UINT32 XFONT_MatchFIList( fontMatch* pfm )
1411 BOOL32 skipRaster = (pfm->flags & FO_MATCH_NORASTER);
1412 UINT32 current_score, score = (UINT32)(-1);
1413 fontMatch fm = *pfm;
1415 for( fm.pfi = pfm->pfr->fi; fm.pfi && score; fm.pfi = fm.pfi->next )
1417 if( skipRaster && !(fm.pfi->fi_flags & FI_SCALABLE) )
1420 current_score = XFONT_Match( &fm );
1421 if( score > current_score )
1423 memcpy( pfm, &fm, sizeof(fontMatch) );
1424 score = current_score;
1430 /***********************************************************************
1431 * XFONT_CheckAliasTable
1433 static LPSTR XFONT_CheckAliasTable( LPSTR lpAlias )
1437 for( fa = aliasTable; fa; fa = fa->next )
1438 if( !lstrcmpi32A( fa->faAlias, lpAlias ) ) return fa->faTypeFace;
1442 /***********************************************************************
1445 * REMOVE_SUBSETS - attach new fi and purge subsets
1446 * UNMARK_SUBSETS - remove subset flags from all fi entries
1448 static void XFONT_CheckFIList( fontResource* fr, fontInfo* fi, int action)
1451 fontInfo* pfi, *prev;
1453 for( prev = NULL, pfi = fr->fi; pfi; )
1455 if( action == REMOVE_SUBSETS )
1457 if( pfi->fi_flags & FI_SUBSET )
1459 fontInfo* subset = pfi;
1463 if( prev ) prev->next = pfi = pfi->next;
1464 else fr->fi = pfi = pfi->next;
1465 HeapFree( SystemHeap, 0, subset );
1469 else pfi->fi_flags &= ~FI_SUBSET;
1475 if( action == REMOVE_SUBSETS ) /* also add the superset */
1477 if( fi->fi_flags & FI_SCALABLE )
1482 else if( prev ) prev->next = fi; else fr->fi = fi;
1486 #ifdef DEBUG_FONT_INIT
1487 if( i ) dprintf_font(stddeb,"\t purged %i subsets [%i]\n", i , fr->count);
1491 /***********************************************************************
1494 static fontResource* XFONT_FindFIList( fontResource* pfr, const char* pTypeFace )
1498 if( !lstrcmpi32A( pfr->lfFaceName, pTypeFace ) ) break;
1504 /***********************************************************************
1505 * XFONT_MatchDeviceFont
1507 * Scan font resource tree.
1509 static BOOL32 XFONT_MatchDeviceFont( fontResource* start, fontMatch* pfm )
1511 fontMatch fm = *pfm;
1514 if( fm.plf->lfFaceName[0] )
1516 LPSTR str = XFONT_CheckAliasTable( fm.plf->lfFaceName );
1517 fm.pfr = XFONT_FindFIList( start, str ? str : fm.plf->lfFaceName );
1520 if( fm.pfr ) /* match family */
1522 dprintf_font(stddeb, "%s\n", fm.pfr->lfFaceName );
1524 XFONT_MatchFIList( &fm );
1528 if( !pfm->pfi ) /* match all available fonts */
1530 UINT32 current_score, score = (UINT32)(-1);
1532 fm.flags |= FO_MATCH_PAF;
1533 for( start = fontList; start && score; start = start->next )
1536 dprintf_font(stddeb, "%s\n", fm.pfr->lfFaceName );
1538 current_score = XFONT_MatchFIList( &fm );
1539 if( current_score < score )
1541 score = current_score;
1550 /***********************************************************************
1553 static void XFONT_GrowFreeList(int start, int end)
1555 /* add all entries from 'start' up to and including 'end' */
1557 memset( fontCache + start, 0, (end - start + 1) * sizeof(fontObject) );
1559 fontCache[end].lru = fontLF;
1560 fontCache[end].count = -1;
1562 while( start < end )
1564 fontCache[start].count = -1;
1565 fontCache[start].lru = start + 1;
1570 static fontObject* XFONT_LookupCachedFont( LPLOGFONT16 plf, UINT16* checksum )
1572 UINT16 cs = __lfCheckSum( plf );
1573 int i = fontMRU, prev = -1;
1578 if( fontCache[i].lfchecksum == cs &&
1579 !(fontCache[i].fo_flags & FO_REMOVED) )
1581 /* FIXME: something more intelligent here */
1583 if( !memcmp( plf, &fontCache[i].lf,
1584 sizeof(LOGFONT16) - LF_FACESIZE ) &&
1585 !lstrncmpi32A( plf->lfFaceName, fontCache[i].lf.lfFaceName,
1588 /* remove temporarily from the lru list */
1591 fontCache[prev].lru = fontCache[i].lru;
1593 fontMRU = (INT16)fontCache[i].lru;
1594 return (fontCache + i);
1598 i = (INT16)fontCache[i].lru;
1603 static fontObject* XFONT_GetCacheEntry()
1609 int prev_i, prev_j, j;
1611 dprintf_font(stddeb,"font cache is full\n");
1613 /* lookup the least recently used font */
1615 for( prev_i = prev_j = j = -1, i = fontMRU; i >= 0; i = (INT16)fontCache[i].lru )
1617 if( fontCache[i].count <= 0 &&
1618 !(fontCache[i].fo_flags & FO_SYSTEM) )
1626 if( j >= 0 ) /* unload font */
1628 /* detach from the lru list */
1630 dprintf_font(stddeb,"\tfreeing entry %i\n", j );
1633 fontCache[prev_j].lru = fontCache[j].lru;
1634 else fontMRU = (INT16)fontCache[j].lru;
1636 /* FIXME: lpXForm, lpPixmap */
1637 XFreeFont( display, fontCache[j].fs );
1639 memset( fontCache + j, 0, sizeof(fontObject) );
1640 return (fontCache + j);
1642 else /* expand cache */
1644 fontObject* newCache;
1646 prev_i = fontCacheSize + FONTCACHE;
1648 dprintf_font(stddeb,"\tgrowing font cache from %i to %i\n", fontCacheSize, prev_i );
1650 if( (newCache = (fontObject*)HeapReAlloc(SystemHeap, 0,
1651 fontCache, prev_i)) )
1654 fontCacheSize = prev_i;
1655 fontCache = newCache;
1656 XFONT_GrowFreeList( i, fontCacheSize - 1);
1662 /* detach from the free list */
1665 fontLF = (INT16)fontCache[i].lru;
1666 fontCache[i].count = 0;
1667 return (fontCache + i);
1670 static int XFONT_ReleaseCacheEntry(fontObject* pfo)
1672 UINT32 u = (UINT32)(pfo - fontCache);
1674 if( u < fontCacheSize ) return (--fontCache[u].count);
1678 /***********************************************************************
1679 * X Device Font Objects
1681 static X_PHYSFONT XFONT_RealizeFont( LPLOGFONT16 plf )
1684 fontObject* pfo = XFONT_LookupCachedFont( plf, &checksum );
1688 fontMatch fm = { NULL, NULL, 0, 0, plf};
1691 if( XTextCaps & TC_SF_X_YINDEP ) fm.flags = FO_MATCH_XYINDEP;
1693 /* allocate new font cache entry */
1695 if( (pfo = XFONT_GetCacheEntry()) )
1697 LPSTR lpLFD = HeapAlloc( GetProcessHeap(), 0, MAX_LFD_LENGTH );
1699 if( lpLFD ) /* initialize entry and load font */
1701 UINT32 uRelaxLevel = 0;
1703 dprintf_font(stddeb,"XRealizeFont: (%u) '%s' h=%i weight=%i %s\n",
1704 plf->lfCharSet, plf->lfFaceName, plf->lfHeight,
1705 plf->lfWeight, (plf->lfItalic) ? "Italic" : "" );
1707 XFONT_MatchDeviceFont( fontList, &fm );
1711 pfo->fo_flags = fm.flags & ~FO_MATCH_MASK;
1713 memcpy( &pfo->lf, plf, sizeof(LOGFONT16) );
1714 pfo->lfchecksum = checksum;
1718 LFD_ComposeLFD( pfo, fm.height, lpLFD, uRelaxLevel++ );
1719 if( (pfo->fs = XLoadQueryFont( display, lpLFD )) ) break;
1720 } while( uRelaxLevel );
1722 if( XFONT_GetLeading( &pfo->fi->df, pfo->fs, &i, NULL ) )
1723 pfo->foAvgCharWidth = (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].width;
1725 pfo->foAvgCharWidth = (INT16)XFONT_GetAvgCharWidth( &pfo->fi->df, pfo->fs );
1726 pfo->foInternalLeading = (INT16)i;
1728 /* FIXME: If we've got a soft font or
1729 * there are FO_SYNTH_... flags for the
1730 * non PROOF_QUALITY request, the engine
1731 * should rasterize characters into mono
1732 * pixmaps and store them in the pfo->lpPixmap
1733 * array (pfo->fs should be updated as well).
1734 * X11DRV_ExtTextOut() must be heavily modified
1735 * to support pixmap blitting and FO_SYNTH_...
1739 pfo->lpXForm = NULL;
1740 pfo->lpPixmap = NULL;
1742 HeapFree( GetProcessHeap(), 0, lpLFD );
1744 else /* attach back to the free list */
1748 fontLF = (pfo - fontCache);
1753 if( !pfo ) /* couldn't get a new entry, get one of the cached fonts */
1755 UINT32 current_score, score = (UINT32)(-1);
1757 i = index = fontMRU;
1758 fm.flags |= FO_MATCH_PAF;
1761 pfo = fontCache + i;
1762 fm.pfr = pfo->fr; fm.pfi = pfo->fi;
1764 current_score = XFONT_Match( &fm );
1765 if( current_score < score ) index = i;
1769 pfo = fontCache + index;
1771 return (X_PHYSFONT)(X_PFONT_MAGIC | index);
1775 /* attach at the head of the lru list */
1779 fontMRU = (pfo - fontCache);
1781 dprintf_font(stddeb,"physfont %i\n", fontMRU);
1783 return (X_PHYSFONT)(X_PFONT_MAGIC | fontMRU);
1786 /***********************************************************************
1787 * XFONT_GetFontObject
1789 fontObject* XFONT_GetFontObject( X_PHYSFONT pFont )
1791 if( CHECK_PFONT(pFont) ) return __PFONT(pFont);
1795 /***********************************************************************
1796 * XFONT_GetFontStruct
1798 XFontStruct* XFONT_GetFontStruct( X_PHYSFONT pFont )
1800 if( CHECK_PFONT(pFont) ) return __PFONT(pFont)->fs;
1804 /***********************************************************************
1807 LPIFONTINFO16 XFONT_GetFontInfo( X_PHYSFONT pFont )
1809 if( CHECK_PFONT(pFont) ) return &(__PFONT(pFont)->fi->df);
1815 /* X11DRV Interface ****************************************************
1817 * Exposed via the dc->funcs dispatch table. *
1819 ***********************************************************************/
1820 /***********************************************************************
1821 * X11DRV_FONT_SelectObject
1823 HFONT32 X11DRV_FONT_SelectObject( DC* dc, HFONT32 hfont, FONTOBJ* font )
1825 HFONT32 hPrevFont = 0;
1827 if( CHECK_PFONT(dc->u.x.font) )
1828 XFONT_ReleaseCacheEntry( __PFONT(dc->u.x.font) );
1830 dc->u.x.font = XFONT_RealizeFont( &font->logfont );
1831 hPrevFont = dc->w.hFont;
1832 dc->w.hFont = hfont;
1838 /***********************************************************************
1840 * X11DRV_EnumDeviceFonts
1842 BOOL32 X11DRV_EnumDeviceFonts( DC* dc, LPLOGFONT16 plf,
1843 DEVICEFONTENUMPROC proc, LPARAM lp )
1847 fontResource* pfr = fontList;
1850 if( plf->lfFaceName[0] )
1852 pfr = XFONT_FindFIList( pfr, plf->lfFaceName );
1856 for( pfi = pfr->fi; pfi; pfi = pfi->next )
1857 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
1858 XFONT_GetFontMetric( pfi, &lf, &tm ), lp )) )
1864 for( ; pfr ; pfr = pfr->next )
1865 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
1866 XFONT_GetFontMetric( pfr->fi, &lf, &tm ), lp )) )
1874 /***********************************************************************
1875 * X11DRV_GetTextExtentPoint
1877 BOOL32 X11DRV_GetTextExtentPoint( DC *dc, LPCSTR str, INT32 count,
1880 XFontStruct* pfs = XFONT_GetFontStruct( dc->u.x.font );
1883 int dir, ascent, descent;
1886 XTextExtents( pfs, str, count, &dir, &ascent, &descent, &info );
1887 size->cx = abs((info.width + dc->w.breakRem + count * dc->w.charExtra)
1888 * dc->wndExtX / dc->vportExtX);
1889 size->cy = abs((pfs->ascent + pfs->descent) * dc->wndExtY / dc->vportExtY);
1896 /***********************************************************************
1897 * X11DRV_GetTextMetrics
1899 BOOL32 X11DRV_GetTextMetrics(DC *dc, TEXTMETRIC32A *metrics)
1901 if( CHECK_PFONT(dc->u.x.font) )
1903 fontObject* pfo = __PFONT(dc->u.x.font);
1904 XFONT_GetTextMetric( pfo, metrics );
1911 /***********************************************************************
1912 * X11DRV_GetCharWidth
1914 BOOL32 X11DRV_GetCharWidth( DC *dc, UINT32 firstChar, UINT32 lastChar,
1917 XFontStruct* xfs = XFONT_GetFontStruct( dc->u.x.font );
1923 if (xfs->per_char == NULL)
1924 for (i = firstChar; i <= lastChar; i++)
1925 *buffer++ = xfs->min_bounds.width;
1928 XCharStruct *cs, *def;
1929 static XCharStruct __null_char = { 0, 0, 0, 0, 0, 0 };
1931 CI_GET_CHAR_INFO(xfs, xfs->default_char, &__null_char, def);
1933 for (i = firstChar; i <= lastChar; i++)
1935 if (i >= xfs->min_char_or_byte2 && i <= xfs->max_char_or_byte2)
1937 cs = &xfs->per_char[(i - xfs->min_char_or_byte2)];
1938 if (CI_NONEXISTCHAR(cs)) cs = def;
1940 *buffer++ = MAX( cs->width, 0 );
1948 /***********************************************************************
1950 * Font Resource API *
1952 ***********************************************************************/
1953 /***********************************************************************
1954 * AddFontResource16 (GDI.119)
1956 * Can be either .FON, or .FNT, or .TTF, or .FOT font file.
1958 * FIXME: Load header and find the best-matching font in the fontList;
1959 * fixup dfPoints if all metrics are identical, otherwise create
1960 * new fontAlias. When soft font support is ready this will
1961 * simply create a new fontResource ('filename' will go into
1962 * the pfr->resource field) with FR_SOFTFONT/FR_SOFTRESOURCE
1965 INT16 AddFontResource16( LPCSTR filename )
1967 return AddFontResource32A( filename );
1971 /***********************************************************************
1972 * AddFontResource32A (GDI32.2)
1974 INT32 AddFontResource32A( LPCSTR str )
1976 if (HIWORD(str)) /* font file */
1977 fprintf( stdnimp, "STUB: AddFontResource('%s')\n", str );
1978 else /* font resource handle */
1979 fprintf( stdnimp, "STUB: AddFontResource(%04x)\n", LOWORD(str) );
1984 /***********************************************************************
1985 * AddFontResource32W (GDI32.4)
1987 INT32 AddFontResource32W( LPCWSTR str )
1989 fprintf( stdnimp, "STUB: AddFontResource32W(%p)\n", str );
1993 /***********************************************************************
1994 * RemoveFontResource16 (GDI.136)
1996 BOOL16 RemoveFontResource16( LPCSTR str )
1998 return RemoveFontResource32A( str );
2002 /***********************************************************************
2003 * RemoveFontResource32A (GDI32.284)
2005 BOOL32 RemoveFontResource32A( LPCSTR str )
2008 fprintf( stdnimp, "STUB: RemoveFontResource('%s')\n", str );
2010 fprintf( stdnimp, "STUB: RemoveFontResource(%04x)\n", LOWORD(str) );
2015 /***********************************************************************
2016 * RemoveFontResource32W (GDI32.286)
2018 BOOL32 RemoveFontResource32W( LPCWSTR str )
2020 fprintf( stdnimp, "STUB: RemoveFontResource32W(%p)\n", str );