Release 951003
[wine] / objects / font.c
1 /*
2  * GDI font objects
3  *
4  * Copyright 1993 Alexandre Julliard
5  *
6 static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <X11/Xatom.h>
13 #include "font.h"
14 #include "metafile.h"
15 #include "wine.h"
16 #include "callback.h"
17 #include "stddebug.h"
18 #include "debug.h"
19
20 #define MAX_FONTS       256
21 static LPLOGFONT lpLogFontList[MAX_FONTS] = { NULL };
22
23
24 #define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
25                              (((cs)->rbearing|(cs)->lbearing| \
26                                (cs)->ascent|(cs)->descent) == 0))
27
28 /* 
29  * CI_GET_CHAR_INFO - return the charinfo struct for the indicated 8bit
30  * character.  If the character is in the column and exists, then return the
31  * appropriate metrics (note that fonts with common per-character metrics will
32  * return min_bounds).  If none of these hold true, try again with the default
33  * char.
34  */
35 #define CI_GET_CHAR_INFO(fs,col,def,cs) \
36 { \
37     cs = def; \
38     if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
39         if (fs->per_char == NULL) { \
40             cs = &fs->min_bounds; \
41         } else { \
42             cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
43             if (CI_NONEXISTCHAR(cs)) cs = def; \
44         } \
45     } \
46 }
47
48 #define CI_GET_DEFAULT_INFO(fs,cs) \
49   CI_GET_CHAR_INFO(fs, fs->default_char, NULL, cs)
50
51 struct FontStructure {
52         char *window;
53         char *x11;
54 } FontNames[32];
55 int FontSize;
56
57
58 /***********************************************************************
59  *           FONT_Init
60  */
61 BOOL FONT_Init( void )
62 {
63   char  temp[1024];
64   LPSTR ptr;
65   int i;
66
67   if( GetPrivateProfileString("fonts", NULL, "*", temp, sizeof(temp), WINE_INI) > 2 ) {
68     for( ptr = temp, i = 1; strlen(ptr) != 0; ptr += strlen(ptr) + 1 )
69       if( strcmp( ptr, "default" ) )
70         FontNames[i++].window = strdup( ptr );
71     FontSize = i;
72
73     for( i = 1; i < FontSize; i++ ) {
74       GetPrivateProfileString("fonts", FontNames[i].window, "*", temp, sizeof(temp), WINE_INI);
75       FontNames[i].x11 = strdup( temp );
76     }
77     GetPrivateProfileString("fonts", "default", "*", temp, sizeof(temp), WINE_INI);
78     FontNames[0].x11 = strdup( temp );
79
80   } else {
81     FontNames[0].window = NULL; FontNames[0].x11 = "*-helvetica";
82     FontNames[1].window = "ms sans serif"; FontNames[1].x11 = "*-helvetica";
83     FontNames[2].window = "ms serif"; FontNames[2].x11 = "*-times";
84     FontNames[3].window = "fixedsys"; FontNames[3].x11 = "*-fixed";
85     FontNames[4].window = "arial"; FontNames[4].x11 = "*-helvetica";
86     FontNames[5].window = "helv"; FontNames[5].x11 = "*-helvetica";
87     FontNames[6].window = "roman"; FontNames[6].x11 = "*-times";
88     FontSize = 7;
89   }
90   return TRUE;
91 }
92
93
94 /***********************************************************************
95  *           FONT_TranslateName
96  *
97  * Translate a Windows face name to its X11 equivalent.
98  * This will probably have to be customizable.
99  */
100 static const char *FONT_TranslateName( char *winFaceName )
101 {
102   int i;
103
104   for (i = 1; i < FontSize; i ++)
105     if( !strcmp( winFaceName, FontNames[i].window ) ) {
106       dprintf_font(stddeb, "---- Mapped %s to %s\n", winFaceName, FontNames[i].x11 );
107       return FontNames[i].x11;
108     }
109   return FontNames[0].x11;
110 }
111
112
113 /***********************************************************************
114  *           FONT_MatchFont
115  *
116  * Find a X font matching the logical font.
117  */
118 static XFontStruct * FONT_MatchFont( LOGFONT * font, DC * dc )
119 {
120     char pattern[100];
121     const char *family, *weight, *charset;
122     char **names;
123     char slant, spacing;
124     int width, height, oldheight, count;
125     XFontStruct * fontStruct;
126     
127     weight = (font->lfWeight > 550) ? "bold" : "medium";
128     slant = font->lfItalic ? 'i' : 'r';
129     height = font->lfHeight * dc->w.VportExtX / dc->w.WndExtX;
130     if (height == 0) height = 120;  /* Default height = 12 */
131     else if (height < 0)
132     {
133           /* If height is negative, it means the height of the characters */
134           /* *without* the internal leading. So we adjust it a bit to     */
135           /* compensate. 5/4 seems to give good results for small fonts.  */
136         height = 10 * (-height * 5 / 4);
137     }
138     else height *= 10;
139     width  = 10 * (font->lfWidth * dc->w.VportExtY / dc->w.WndExtY);
140     if (width < 0) {
141         dprintf_font( stddeb, "FONT_MatchFont: negative width %d(%d)\n",
142                       width, font->lfWidth );
143         width = -width;
144     }
145     spacing = (font->lfPitchAndFamily & FIXED_PITCH) ? 'm' :
146               (font->lfPitchAndFamily & VARIABLE_PITCH) ? 'p' : '*';
147     charset = (font->lfCharSet == ANSI_CHARSET) ? "iso8859-1" : "*-*";
148     if (*font->lfFaceName) family = FONT_TranslateName( font->lfFaceName );
149     else switch(font->lfPitchAndFamily & 0xf0)
150     {
151     case FF_ROMAN:
152       family = FONT_TranslateName( "roman" );
153       break;
154     case FF_SWISS:
155       family = FONT_TranslateName( "swiss" );
156       break;
157     case FF_MODERN:
158       family = FONT_TranslateName( "modern" );
159       break;
160     case FF_SCRIPT:
161       family = FONT_TranslateName( "script" );
162       break;
163     case FF_DECORATIVE:
164       family = FONT_TranslateName( "decorative" );
165       break;
166     default:
167       family = "*-*";
168       break;
169     }
170     
171     oldheight = height;
172     while (TRUE) {
173             /* Width==0 seems not to be a valid wildcard on SGI's, using * instead */
174             if ( width == 0 )
175               sprintf( pattern, "-%s-%s-%c-normal-*-*-%d-*-*-%c-*-%s",
176                       family, weight, slant, height, spacing, charset);
177             else
178               sprintf( pattern, "-%s-%s-%c-normal-*-*-%d-*-*-%c-%d-%s",
179                       family, weight, slant, height, spacing, width, charset);
180             dprintf_font(stddeb, "FONT_MatchFont: '%s'\n", pattern );
181             names = XListFonts( display, pattern, 1, &count );
182             if (count > 0) break;
183             height -= 10;               
184             if (height < 10) {
185                 dprintf_font(stddeb,"*** No match for %s\n", pattern );
186                 if(slant == 'i') {
187                     /* try oblique if no italic font */
188                     slant = 'o';
189                     height = oldheight;
190                     continue;
191                 }
192                 if (spacing == 'm') {
193                     /* If a fixed spacing font could not be found, ignore
194                      * the family */
195                     family = "*-*";
196                     height = oldheight;
197                     continue;
198                 }
199                 return NULL;
200             }
201     }
202     dprintf_font(stddeb,"        Found '%s'\n", *names );
203     fontStruct = XLoadQueryFont( display, *names );
204     XFreeFontNames( names );
205     return fontStruct;
206 }
207
208
209 /***********************************************************************
210  *           FONT_GetMetrics
211  */
212 void FONT_GetMetrics( LOGFONT * logfont, XFontStruct * xfont,
213                       TEXTMETRIC * metrics )
214 {    
215     int average, i, count;
216     unsigned long prop;
217         
218     metrics->tmAscent  = xfont->ascent;
219     metrics->tmDescent = xfont->descent;
220     metrics->tmHeight  = xfont->ascent + xfont->descent;
221
222     metrics->tmInternalLeading  = 0;
223     if (XGetFontProperty( xfont, XA_X_HEIGHT, &prop ))
224         metrics->tmInternalLeading = xfont->ascent - (short)prop;
225     metrics->tmExternalLeading  = 0;
226     metrics->tmMaxCharWidth     = xfont->max_bounds.width;
227     metrics->tmWeight           = logfont->lfWeight;
228     metrics->tmItalic           = logfont->lfItalic;
229     metrics->tmUnderlined       = logfont->lfUnderline;
230     metrics->tmStruckOut        = logfont->lfStrikeOut;
231     metrics->tmFirstChar        = xfont->min_char_or_byte2;
232     metrics->tmLastChar         = xfont->max_char_or_byte2;
233     metrics->tmDefaultChar      = xfont->default_char;
234     metrics->tmBreakChar        = ' ';
235     metrics->tmCharSet          = logfont->lfCharSet;
236     metrics->tmOverhang         = 0;
237     metrics->tmDigitizedAspectX = 1;
238     metrics->tmDigitizedAspectY = 1;
239     metrics->tmPitchAndFamily   = (logfont->lfPitchAndFamily&0xf0)|TMPF_DEVICE;
240     if (logfont->lfPitchAndFamily & FIXED_PITCH) 
241         metrics->tmPitchAndFamily |= TMPF_FIXED_PITCH;
242
243     if (!xfont->per_char) average = metrics->tmMaxCharWidth;
244     else
245     {
246         XCharStruct * charPtr = xfont->per_char;
247         average = count = 0;
248         for (i = metrics->tmFirstChar; i <= metrics->tmLastChar; i++)
249         {
250             if (!CI_NONEXISTCHAR( charPtr ))
251             {
252                 average += charPtr->width;
253                 count++;
254             }
255             charPtr++;
256         }
257         if (count) average = (average + count/2) / count;
258     }
259     metrics->tmAveCharWidth = average;
260 }
261
262 /***********************************************************************
263  *           GetGlyphOutLine    (GDI.309)
264  */
265 DWORD GetGlyphOutLine(HDC hdc, UINT uChar, UINT fuFormat, LPGLYPHMETRICS lpgm, 
266                       DWORD cbBuffer, LPSTR lpBuffer, LPMAT2 lpmat2) 
267 {
268     fprintf( stdnimp,"GetGlyphOutLine("NPFMT", '%c', %04x, %p, %ld, %p, %p) // - empty stub!\n",
269              hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
270     return (DWORD)-1; /* failure */
271 }
272
273
274 /***********************************************************************
275  *           CreateScalableFontResource    (GDI.310)
276  */
277 BOOL CreateScalableFontResource( UINT fHidden,LPSTR lpszResourceFile,
278                                  LPSTR lpszFontFile, LPSTR lpszCurrentPath )
279 {
280     /* fHidden=1 - only visible for the calling app, read-only, not
281      * enumbered with EnumFonts/EnumFontFamilies
282      * lpszCurrentPath can be NULL
283      */
284     fprintf(stdnimp,"CreateScalableFontResource(%d,%s,%s,%s) // empty stub!\n",
285             fHidden, lpszResourceFile, lpszFontFile, lpszCurrentPath );
286     return FALSE; /* create failed */
287 }
288
289
290 /***********************************************************************
291  *           CreateFontIndirect    (GDI.57)
292  */
293 HFONT CreateFontIndirect( LOGFONT * font )
294 {
295     FONTOBJ * fontPtr;
296     HFONT hfont = GDI_AllocObject( sizeof(FONTOBJ), FONT_MAGIC );
297     if (!hfont) return 0;
298     fontPtr = (FONTOBJ *) GDI_HEAP_LIN_ADDR( hfont );
299     memcpy( &fontPtr->logfont, font, sizeof(LOGFONT) );
300     AnsiLower( fontPtr->logfont.lfFaceName );
301     dprintf_font(stddeb,"CreateFontIndirect(%p); return "NPFMT"\n",font,hfont);
302     return hfont;
303 }
304
305
306 /***********************************************************************
307  *           CreateFont    (GDI.56)
308  */
309 HFONT CreateFont( int height, int width, int esc, int orient, int weight,
310                   BYTE italic, BYTE underline, BYTE strikeout, BYTE charset,
311                   BYTE outpres, BYTE clippres, BYTE quality, BYTE pitch,
312                   LPSTR name )
313 {
314     LOGFONT logfont = { height, width, esc, orient, weight, italic, underline,
315                     strikeout, charset, outpres, clippres, quality, pitch, };
316     if (name) strncpy( logfont.lfFaceName, name, LF_FACESIZE );
317     else logfont.lfFaceName[0] = '\0';
318     return CreateFontIndirect( &logfont );
319 }
320
321
322 /***********************************************************************
323  *           FONT_GetObject
324  */
325 int FONT_GetObject( FONTOBJ * font, int count, LPSTR buffer )
326 {
327     if (count > sizeof(LOGFONT)) count = sizeof(LOGFONT);
328     memcpy( buffer, &font->logfont, count );
329     return count;
330 }
331
332
333 /***********************************************************************
334  *           FONT_SelectObject
335  */
336 HFONT FONT_SelectObject( DC * dc, HFONT hfont, FONTOBJ * font )
337 {
338     static X_PHYSFONT stockFonts[LAST_STOCK_FONT-FIRST_STOCK_FONT+1];
339     X_PHYSFONT * stockPtr;
340     HFONT prevHandle = dc->w.hFont;
341     XFontStruct * fontStruct;
342     dprintf_font(stddeb,"FONT_SelectObject(%p, "NPFMT", %p)\n", 
343                      dc, hfont, font);
344       /* Load font if necessary */
345
346     if (!font)
347     {
348         HFONT hnewfont;
349
350         hnewfont = CreateFont(10, 7, 0, 0, FW_DONTCARE,
351                               FALSE, FALSE, FALSE, DEFAULT_CHARSET, 0, 0,
352                               DEFAULT_QUALITY, FF_DONTCARE, "*" );
353         font = (FONTOBJ *) GDI_HEAP_LIN_ADDR( hnewfont );
354     }
355
356     if (dc->header.wMagic == METAFILE_DC_MAGIC)
357       if (MF_CreateFontIndirect(dc, hfont, &(font->logfont)))
358         return prevHandle;
359       else
360         return 0;
361
362       /*  Must be DWORD for WINELIB32 support  */
363     if ((hfont >= FIRST_STOCK_FONT) && (hfont <= LAST_STOCK_FONT))
364         stockPtr = &stockFonts[(DWORD)hfont - (DWORD)FIRST_STOCK_FONT];
365     else 
366         stockPtr = NULL;
367     
368     if (!stockPtr || !stockPtr->fstruct)
369     {
370         if (!(fontStruct = FONT_MatchFont( &font->logfont, dc )))
371         {
372               /* If it is not a stock font, we can simply return 0 */
373             if (!stockPtr) return 0;
374               /* Otherwise we must try to find a substitute */
375             dprintf_font(stddeb,"Loading font 'fixed' for "NPFMT"\n", hfont );
376             font->logfont.lfPitchAndFamily &= ~VARIABLE_PITCH;
377             font->logfont.lfPitchAndFamily |= FIXED_PITCH;
378             fontStruct = XLoadQueryFont( display, "fixed" );
379             if (!fontStruct)
380             {
381                 fprintf( stderr, "No system font could be found. Please check your font path.\n" );
382                 exit( 1 );
383             }
384         }
385     }
386     else
387     {
388         fontStruct = stockPtr->fstruct;
389         dprintf_font(stddeb,
390                      "FONT_SelectObject: Loaded font from cache "NPFMT" %p\n",
391                      hfont, fontStruct );
392     }   
393
394       /* Free previous font */
395
396     if ((prevHandle < FIRST_STOCK_FONT) || (prevHandle > LAST_STOCK_FONT))
397     {
398         if (dc->u.x.font.fstruct)
399             XFreeFont( display, dc->u.x.font.fstruct );
400     }
401
402       /* Store font */
403
404     dc->w.hFont = hfont;
405     if (stockPtr)
406     {
407         if (!stockPtr->fstruct)
408         {
409             stockPtr->fstruct = fontStruct;
410             FONT_GetMetrics( &font->logfont, fontStruct, &stockPtr->metrics );
411         }
412         memcpy( &dc->u.x.font, stockPtr, sizeof(*stockPtr) );
413     }
414     else
415     {
416         dc->u.x.font.fstruct = fontStruct;
417         FONT_GetMetrics( &font->logfont, fontStruct, &dc->u.x.font.metrics );
418     }
419     return prevHandle;
420 }
421
422
423 /***********************************************************************
424  *           GetTextCharacterExtra    (GDI.89)
425  */
426 short GetTextCharacterExtra( HDC hdc )
427 {
428     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
429     if (!dc) return 0;
430     return abs( (dc->w.charExtra * dc->w.WndExtX + dc->w.VportExtX / 2)
431                  / dc->w.VportExtX );
432 }
433
434
435 /***********************************************************************
436  *           SetTextCharacterExtra    (GDI.8)
437  */
438 short SetTextCharacterExtra( HDC hdc, short extra )
439 {
440     short prev;
441     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
442     if (!dc) return 0;
443     extra = (extra * dc->w.VportExtX + dc->w.WndExtX / 2) / dc->w.WndExtX;    
444     prev = dc->w.charExtra;
445     dc->w.charExtra = abs(extra);
446     return (prev * dc->w.WndExtX + dc->w.VportExtX / 2) / dc->w.VportExtX;
447 }
448
449
450 /***********************************************************************
451  *           SetTextJustification    (GDI.10)
452  */
453 short SetTextJustification( HDC hdc, short extra, short breaks )
454 {
455     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
456     if (!dc) return 0;
457
458     extra = abs((extra * dc->w.VportExtX + dc->w.WndExtX / 2) / dc->w.WndExtX);
459     if (!extra) breaks = 0;
460     dc->w.breakTotalExtra = extra;
461     dc->w.breakCount = breaks;
462     if (breaks)
463     {   
464         dc->w.breakExtra = extra / breaks;
465         dc->w.breakRem   = extra - (dc->w.breakCount * dc->w.breakExtra);
466     }
467     else
468     {
469         dc->w.breakExtra = 0;
470         dc->w.breakRem   = 0;
471     }
472     return 1;
473 }
474
475
476 /***********************************************************************
477  *           GetTextFace    (GDI.92)
478  */
479 INT GetTextFace( HDC hdc, INT count, LPSTR name )
480 {
481     FONTOBJ *font;
482
483     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
484     if (!dc) return 0;
485     if (!(font = (FONTOBJ *) GDI_GetObjPtr( dc->w.hFont, FONT_MAGIC )))
486         return 0;
487     strncpy( name, font->logfont.lfFaceName, count );
488     name[count-1] = '\0';
489     return strlen(name);
490 }
491
492
493 /***********************************************************************
494  *           GetTextExtent    (GDI.91)
495  */
496 DWORD GetTextExtent( HDC hdc, LPSTR str, short count )
497 {
498     SIZE size;
499     if (!GetTextExtentPoint( hdc, str, count, &size )) return 0;
500     return MAKELONG( size.cx, size.cy );
501 }
502
503
504 /***********************************************************************
505  *           GetTextExtentPoint    (GDI.471)
506  */
507 BOOL GetTextExtentPoint( HDC hdc, LPSTR str, short count, LPSIZE size )
508 {
509     int dir, ascent, descent;
510     XCharStruct info;
511
512     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
513     if (!dc) return FALSE;
514     XTextExtents( dc->u.x.font.fstruct, str, count, &dir,
515                   &ascent, &descent, &info );
516     size->cx = abs((info.width + dc->w.breakRem + count * dc->w.charExtra)
517                     * dc->w.WndExtX / dc->w.VportExtX);
518     size->cy = abs((dc->u.x.font.fstruct->ascent+dc->u.x.font.fstruct->descent)
519                     * dc->w.WndExtY / dc->w.VportExtY);
520
521     dprintf_font(stddeb,"GetTextExtentPoint("NPFMT" '%*.*s' %d %p): returning %d,%d\n",
522             hdc, count, count, str, count, size, size->cx, size->cy );
523     return TRUE;
524 }
525
526
527 /***********************************************************************
528  *           GetTextMetrics    (GDI.93)
529  */
530 BOOL GetTextMetrics( HDC hdc, LPTEXTMETRIC metrics )
531 {
532     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
533     if (!dc) return FALSE;
534     memcpy( metrics, &dc->u.x.font.metrics, sizeof(*metrics) );
535
536     metrics->tmAscent  = abs( metrics->tmAscent
537                               * dc->w.WndExtY / dc->w.VportExtY );
538     metrics->tmDescent = abs( metrics->tmDescent
539                               * dc->w.WndExtY / dc->w.VportExtY );
540     metrics->tmHeight  = metrics->tmAscent + metrics->tmDescent;
541     metrics->tmInternalLeading = abs( metrics->tmInternalLeading
542                                       * dc->w.WndExtY / dc->w.VportExtY );
543     metrics->tmExternalLeading = abs( metrics->tmExternalLeading
544                                       * dc->w.WndExtY / dc->w.VportExtY );
545     metrics->tmMaxCharWidth    = abs( metrics->tmMaxCharWidth 
546                                       * dc->w.WndExtX / dc->w.VportExtX );
547     metrics->tmAveCharWidth    = abs( metrics->tmAveCharWidth
548                                       * dc->w.WndExtX / dc->w.VportExtX );
549     return TRUE;
550 }
551
552
553 /***********************************************************************
554  *           SetMapperFlags    (GDI.349)
555  */
556 DWORD SetMapperFlags(HDC hDC, DWORD dwFlag)
557 {
558     dprintf_font(stdnimp,"SetmapperFlags("NPFMT", %08lX) // Empty Stub !\n", 
559                  hDC, dwFlag); 
560     return 0L;
561 }
562
563  
564 /***********************************************************************/
565
566
567 /***********************************************************************
568  *           GetCharWidth    (GDI.350)
569  */
570 BOOL GetCharWidth(HDC hdc, WORD wFirstChar, WORD wLastChar, LPINT lpBuffer)
571 {
572     int i, j;
573     XFontStruct *xfont;
574     XCharStruct *cs, *def;
575
576     DC *dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC);
577     if (!dc) return FALSE;
578     xfont = dc->u.x.font.fstruct;
579     
580     /* fixed font? */
581     if (xfont->per_char == NULL)
582     {
583         for (i = wFirstChar, j = 0; i <= wLastChar; i++, j++)
584             *(lpBuffer + j) = xfont->max_bounds.width;
585         return TRUE;
586     }
587
588     CI_GET_DEFAULT_INFO(xfont, def);
589         
590     for (i = wFirstChar, j = 0; i <= wLastChar; i++, j++)
591     {
592         CI_GET_CHAR_INFO(xfont, i, def, cs);
593         *(lpBuffer + j) = cs ? cs->width : xfont->max_bounds.width;
594         if (*(lpBuffer + j) < 0)
595             *(lpBuffer + j) = 0;
596     }
597     return TRUE;
598 }
599
600
601 /***********************************************************************
602  *           AddFontResource    (GDI.119)
603  */
604 INT AddFontResource( LPCSTR str )
605 {
606     fprintf( stdnimp, "STUB: AddFontResource('%s')\n", str );
607     return 1;
608 }
609
610
611 /***********************************************************************
612  *           RemoveFontResource    (GDI.136)
613  */
614 BOOL RemoveFontResource( LPSTR str )
615 {
616     fprintf( stdnimp, "STUB: RemoveFontResource('%s')\n", str );
617     return TRUE;
618 }
619
620
621 /*************************************************************************
622  *                              ParseFontParms          [internal]
623  */
624 int ParseFontParms(LPSTR lpFont, WORD wParmsNo, LPSTR lpRetStr, WORD wMaxSiz)
625 {
626         int     i;
627         dprintf_font(stddeb,"ParseFontParms('%s', %d, %p, %d);\n", 
628                         lpFont, wParmsNo, lpRetStr, wMaxSiz);
629         if (lpFont == NULL) return 0;
630         if (lpRetStr == NULL) return 0;
631         for (i = 0; (*lpFont != '\0' && i != wParmsNo); ) {
632                 if (*lpFont == '-') i++;
633                 lpFont++;
634                 }
635         if (i == wParmsNo) {
636                 if (*lpFont == '-') lpFont++;
637                 wMaxSiz--;
638                 for (i = 0; (*lpFont != '\0' && *lpFont != '-' && i < wMaxSiz); i++)
639                         *(lpRetStr + i) = *lpFont++;
640                 *(lpRetStr + i) = '\0';
641                 dprintf_font(stddeb,"ParseFontParms // '%s'\n", lpRetStr);
642                 return i;
643                 }
644         else
645                 lpRetStr[0] = '\0';
646         return 0;
647 }
648
649
650 /*************************************************************************
651  *                              InitFontsList           [internal]
652  */
653
654 static int logfcmp(const void *a,const void *b) 
655 {
656   return strcmp( (*(LPLOGFONT *)a)->lfFaceName, (*(LPLOGFONT *)b)->lfFaceName );
657 }
658
659 void InitFontsList(void)
660 {
661   char  str[32];
662   char  pattern[100];
663   char  *family, *weight, *charset;
664   char  **names;
665   char  slant, spacing;
666   int   i, count;
667   LPLOGFONT lpNewFont;
668   weight = "medium";
669   slant = 'r';
670   spacing = '*';
671   charset = "*";
672   family = "*-*";
673   dprintf_font(stddeb,"InitFontsList !\n");
674   sprintf( pattern, "-%s-%s-%c-normal-*-*-*-*-*-%c-*-%s",
675           family, weight, slant, spacing, charset);
676   names = XListFonts( display, pattern, MAX_FONTS, &count );
677   dprintf_font(stddeb,"InitFontsList // count=%d \n", count);
678   for (i = 0; i < count; i++) {
679     lpNewFont = malloc(sizeof(LOGFONT) + LF_FACESIZE);
680     if (lpNewFont == NULL) {
681       dprintf_font(stddeb, "InitFontsList // Error alloc new font structure !\n");
682       break;
683     }
684     dprintf_font(stddeb,"InitFontsList // names[%d]='%s' \n", i, names[i]);
685     ParseFontParms(names[i], 2, str, sizeof(str));
686     if (strcmp(str, "fixed") == 0) strcat(str, "sys");
687     AnsiUpper(str);
688     strcpy(lpNewFont->lfFaceName, str);
689     ParseFontParms(names[i], 8, str, sizeof(str));
690     lpNewFont->lfHeight = atoi(str) / 10;
691     ParseFontParms(names[i], 12, str, sizeof(str));
692     lpNewFont->lfWidth = atoi(str) / 10;
693     lpNewFont->lfEscapement = 0;
694     lpNewFont->lfOrientation = 0;
695     lpNewFont->lfWeight = FW_REGULAR;
696     lpNewFont->lfItalic = 0;
697     lpNewFont->lfUnderline = 0;
698     lpNewFont->lfStrikeOut = 0;
699     ParseFontParms(names[i], 13, str, sizeof(str));
700     if (strcmp(str, "iso8859") == 0)  {
701       lpNewFont->lfCharSet = ANSI_CHARSET;
702     } else  {
703       lpNewFont->lfCharSet = OEM_CHARSET;
704     }
705     lpNewFont->lfOutPrecision = OUT_DEFAULT_PRECIS;
706     lpNewFont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
707     lpNewFont->lfQuality = DEFAULT_QUALITY;
708     ParseFontParms(names[i], 11, str, sizeof(str));
709     switch(str[0]) {
710      case 'p':
711       lpNewFont->lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
712       break;
713      case 'm':
714       lpNewFont->lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
715       break;
716      default:
717       lpNewFont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
718       break;
719     }
720     dprintf_font(stddeb,"InitFontsList // lpNewFont->lfHeight=%d \n", lpNewFont->lfHeight);
721     dprintf_font(stddeb,"InitFontsList // lpNewFont->lfWidth=%d \n", lpNewFont->lfWidth);
722     dprintf_font(stddeb,"InitFontsList // lfFaceName='%s' \n", lpNewFont->lfFaceName);
723     lpLogFontList[i] = lpNewFont;
724     lpLogFontList[i+1] = NULL;
725   }
726   qsort(lpLogFontList,count,sizeof(*lpLogFontList),logfcmp);
727   XFreeFontNames(names);
728 }
729
730
731 /*************************************************************************
732  *                              EnumFonts                       [GDI.70]
733  */
734 int EnumFonts(HDC hDC, LPSTR lpFaceName, FARPROC lpEnumFunc, LPSTR lpData)
735 {
736   HANDLE       hLog;
737   HANDLE       hMet;
738   HFONT        hFont;
739   HFONT        hOldFont;
740   LPLOGFONT    lpLogFont;
741   LPTEXTMETRIC lptm;
742   LPSTR        lpOldName;
743   char         FaceName[LF_FACESIZE];
744   int          nRet = 0;
745   int          i;
746   
747   dprintf_font(stddeb,"EnumFonts("NPFMT", %p='%s', %08lx, %p)\n", 
748                hDC, lpFaceName, lpFaceName, (LONG)lpEnumFunc, lpData);
749   if (lpEnumFunc == 0) return 0;
750   hLog = GDI_HEAP_ALLOC( sizeof(LOGFONT) + LF_FACESIZE );
751   lpLogFont = (LPLOGFONT) GDI_HEAP_LIN_ADDR(hLog);
752   if (lpLogFont == NULL) {
753     fprintf(stderr,"EnumFonts // can't alloc LOGFONT struct !\n");
754     return 0;
755   }
756   hMet = GDI_HEAP_ALLOC( sizeof(TEXTMETRIC) );
757   lptm = (LPTEXTMETRIC) GDI_HEAP_LIN_ADDR(hMet);
758   if (lptm == NULL) {
759     GDI_HEAP_FREE(hLog);
760     fprintf(stderr, "EnumFonts // can't alloc TEXTMETRIC struct !\n");
761     return 0;
762   }
763   if (lpFaceName != NULL) {
764     strcpy(FaceName, lpFaceName);
765     AnsiUpper(FaceName);
766   } 
767   lpOldName = NULL;
768   
769   if (lpLogFontList[0] == NULL) InitFontsList();
770   for(i = 0; lpLogFontList[i] != NULL; i++) {
771     if (lpFaceName == NULL) {
772       if (lpOldName != NULL) {
773         if (strcmp(lpOldName,lpLogFontList[i]->lfFaceName) == 0) continue;
774       }
775       lpOldName = lpLogFontList[i]->lfFaceName;
776     } else {
777       if (strcmp(FaceName, lpLogFontList[i]->lfFaceName) != 0) continue;
778     }
779     dprintf_font(stddeb,"EnumFonts // enum '%s' !\n", lpLogFontList[i]->lfFaceName);
780     dprintf_font(stddeb,"EnumFonts // %p !\n", lpLogFontList[i]);
781     memcpy(lpLogFont, lpLogFontList[i], sizeof(LOGFONT) + LF_FACESIZE);
782     hFont = CreateFontIndirect(lpLogFont);
783     hOldFont = SelectObject(hDC, hFont);
784     GetTextMetrics(hDC, lptm);
785     SelectObject(hDC, hOldFont);
786     DeleteObject(hFont);
787     dprintf_font(stddeb,"EnumFonts // i=%d lpLogFont=%p lptm=%p\n", i, lpLogFont, lptm);
788     nRet = CallEnumFontsProc(lpEnumFunc, GDI_HEAP_SEG_ADDR(hLog),
789                              GDI_HEAP_SEG_ADDR(hMet), 0, (LONG)lpData );
790     if (nRet == 0) {
791       dprintf_font(stddeb,"EnumFonts // EnumEnd requested by application !\n");
792       break;
793     }
794   }
795   GDI_HEAP_FREE(hMet);
796   GDI_HEAP_FREE(hLog);
797   return nRet;
798 }
799
800
801 /*************************************************************************
802  *                              EnumFontFamilies        [GDI.330]
803  */
804 int EnumFontFamilies(HDC hDC, LPSTR lpszFamily, FARPROC lpEnumFunc, LPSTR lpData)
805 {
806   HANDLE        hLog;
807   HANDLE        hMet;
808   HFONT         hFont;
809   HFONT         hOldFont;
810   LPENUMLOGFONT lpEnumLogFont;
811   LPTEXTMETRIC  lptm;
812   LPSTR         lpOldName;
813   char          FaceName[LF_FACESIZE];
814   int           nRet = 0;
815   int           i;
816   
817   dprintf_font(stddeb,"EnumFontFamilies("NPFMT", %p, %08lx, %p)\n",
818                hDC, lpszFamily, (DWORD)lpEnumFunc, lpData);
819   if (lpEnumFunc == 0) return 0;
820   hLog = GDI_HEAP_ALLOC( sizeof(ENUMLOGFONT) );
821   lpEnumLogFont = (LPENUMLOGFONT) GDI_HEAP_LIN_ADDR(hLog);
822   if (lpEnumLogFont == NULL) {
823     fprintf(stderr,"EnumFontFamilies // can't alloc LOGFONT struct !\n");
824     return 0;
825   }
826   hMet = GDI_HEAP_ALLOC( sizeof(TEXTMETRIC) );
827   lptm = (LPTEXTMETRIC) GDI_HEAP_LIN_ADDR(hMet);
828   if (lptm == NULL) {
829     GDI_HEAP_FREE(hLog);
830     fprintf(stderr,"EnumFontFamilies // can't alloc TEXTMETRIC struct !\n");
831     return 0;
832   }
833   lpOldName = NULL;
834   if (lpszFamily != NULL) {
835     strcpy(FaceName, lpszFamily);
836     AnsiUpper(FaceName);
837   }
838   if (lpLogFontList[0] == NULL) InitFontsList();
839   for(i = 0; lpLogFontList[i] != NULL; i++) {
840     if (lpszFamily == NULL) {
841       if (lpOldName != NULL) {
842         if (strcmp(lpOldName,lpLogFontList[i]->lfFaceName) == 0) continue;
843       }
844       lpOldName = lpLogFontList[i]->lfFaceName;
845     } else {
846       if (strcmp(FaceName, lpLogFontList[i]->lfFaceName) != 0) continue;
847     }
848     memcpy(lpEnumLogFont, lpLogFontList[i], sizeof(LOGFONT));
849     strcpy(lpEnumLogFont->elfFullName,"");
850     strcpy(lpEnumLogFont->elfStyle,"");
851     hFont = CreateFontIndirect((LPLOGFONT)lpEnumLogFont);
852     hOldFont = SelectObject(hDC, hFont);
853     GetTextMetrics(hDC, lptm);
854     SelectObject(hDC, hOldFont);
855     DeleteObject(hFont);
856     dprintf_font(stddeb, "EnumFontFamilies // i=%d lpLogFont=%p lptm=%p\n", i, lpEnumLogFont, lptm);
857     
858     nRet = CallEnumFontFamProc( lpEnumFunc,
859                                GDI_HEAP_SEG_ADDR(hLog),
860                                GDI_HEAP_SEG_ADDR(hMet),
861                                0, (LONG)lpData );
862     if (nRet == 0) {
863       dprintf_font(stddeb,"EnumFontFamilies // EnumEnd requested by application !\n");
864       break;
865     }
866   }
867   GDI_HEAP_FREE(hMet);
868   GDI_HEAP_FREE(hLog);
869   return nRet;
870 }
871
872 /*************************************************************************
873  *                              GetRasterizerCaps       [GDI.313]
874  */
875
876 BOOL GetRasterizerCaps(LPRASTERIZER_STATUS lprs, WORD cbNumBytes)
877 {
878   /* This is not much more than a dummy */
879   RASTERIZER_STATUS rs;
880   
881   rs.nSize = sizeof(rs);
882   rs.wFlags = 0;
883   rs.nLanguageID = 0;
884   return True;
885 }
886
887 /*************************************************************************
888  *             GetKerningPairs      [GDI.332]
889  *  FIXME: The last parameter is actually LPKERNINGPAIR
890  */
891 int GetKerningPairs(WORD hDC,int cBufLen,LPVOID lpKerningPairs)
892 {
893         /* Wine fonts are ugly and don't support kerning :) */
894         return 0;
895 }