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