Release 960805
[wine/multimedia.git] / objects / font.c
blob5cdfd38158a07afad57a86147fd27d07cabdb2d5
1 /*
2 * GDI font objects
4 * Copyright 1993 Alexandre Julliard
6 * Enhacements by Juergen Marquardt 1996
8 * Implementation of a second font cache which
9 * will be updated dynamically
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <X11/Xatom.h>
16 #include "font.h"
17 #include "metafile.h"
18 #include "options.h"
19 #include "string32.h"
20 #include "xmalloc.h"
21 #include "stddebug.h"
22 #include "debug.h"
24 #define FONTCACHE 32 /* dynamic font cache size */
25 #define MAX_FONTS 256
26 static LPLOGFONT16 lpLogFontList[MAX_FONTS+1];
28 static int ParseFontParms(LPSTR lpFont, WORD wParmsNo, LPSTR lpRetStr, WORD wMaxSiz);
30 #define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
31 (((cs)->rbearing|(cs)->lbearing| \
32 (cs)->ascent|(cs)->descent) == 0))
34 /*
35 * CI_GET_CHAR_INFO - return the charinfo struct for the indicated 8bit
36 * character. If the character is in the column and exists, then return the
37 * appropriate metrics (note that fonts with common per-character metrics will
38 * return min_bounds). If none of these hold true, try again with the default
39 * char.
41 #define CI_GET_CHAR_INFO(fs,col,def,cs) \
42 { \
43 cs = def; \
44 if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
45 if (fs->per_char == NULL) { \
46 cs = &fs->min_bounds; \
47 } else { \
48 cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
49 if (CI_NONEXISTCHAR(cs)) cs = def; \
50 } \
51 } \
54 #define CI_GET_DEFAULT_INFO(fs,cs) \
55 CI_GET_CHAR_INFO(fs, fs->default_char, NULL, cs)
57 struct FontStructure {
58 char *window;
59 char *x11;
60 } FontNames[32];
61 int FontSize;
64 /***********************************************************************
65 * FONT_Init
67 BOOL FONT_Init( void )
69 char temp[1024];
70 LPSTR ptr;
71 int i;
73 if (PROFILE_GetWineIniString( "fonts", NULL, "*", temp, sizeof(temp) ) > 2 )
75 for( ptr = temp, i = 1; strlen(ptr) != 0; ptr += strlen(ptr) + 1 )
76 if( strcmp( ptr, "default" ) )
77 FontNames[i++].window = xstrdup( ptr );
78 FontSize = i;
80 for( i = 1; i < FontSize; i++ )
82 PROFILE_GetWineIniString( "fonts", FontNames[i].window, "*",
83 temp, sizeof(temp) );
84 FontNames[i].x11 = xstrdup( temp );
86 PROFILE_GetWineIniString( "fonts", "default", "*", temp, sizeof(temp) );
87 FontNames[0].x11 = xstrdup( temp );
89 } else {
90 FontNames[0].window = NULL; FontNames[0].x11 = "*-helvetica";
91 FontNames[1].window = "ms sans serif"; FontNames[1].x11 = "*-helvetica";
92 FontNames[2].window = "ms serif"; FontNames[2].x11 = "*-times";
93 FontNames[3].window = "fixedsys"; FontNames[3].x11 = "*-fixed";
94 FontNames[4].window = "arial"; FontNames[4].x11 = "*-helvetica";
95 FontNames[5].window = "helv"; FontNames[5].x11 = "*-helvetica";
96 FontNames[6].window = "roman"; FontNames[6].x11 = "*-times";
97 FontSize = 7;
99 return TRUE;
102 /***********************************************************************
103 * FONT_ChkX11Family
105 * returns a valid X11 equivalent if a Windows face name
106 * is like a X11 family - or NULL if translation is needed
108 static char *FONT_ChkX11Family(char *winFaceName )
110 static char x11fam[32+2]; /* will be returned */
111 int i;
113 for(i = 0; lpLogFontList[i] != NULL; i++)
114 if( !lstrcmpi32A(winFaceName, lpLogFontList[i]->lfFaceName) )
116 strcpy(x11fam,"*-");
117 return strcat(x11fam,winFaceName);
119 return NULL; /* a FONT_TranslateName() call is needed */
124 /***********************************************************************
125 * FONT_TranslateName
127 * Translate a Windows face name to its X11 equivalent.
128 * This will probably have to be customizable.
130 static const char *FONT_TranslateName( char *winFaceName )
132 int i;
134 for (i = 1; i < FontSize; i ++)
135 if( !strcmp( winFaceName, FontNames[i].window ) ) {
136 dprintf_font(stddeb, "---- Mapped %s to %s\n", winFaceName, FontNames[i].x11 );
137 return FontNames[i].x11;
139 return FontNames[0].x11;
143 /***********************************************************************
144 * FONT_MatchFont
146 * Find a X font matching the logical font.
148 static XFontStruct * FONT_MatchFont( LOGFONT16 * font, DC * dc )
150 char pattern[100];
151 const char *family, *weight, *charset;
152 char **names;
153 char slant, oldspacing, spacing;
154 int width, height, oldheight, count;
155 XFontStruct * fontStruct;
157 dprintf_font(stddeb,
158 "FONT_MatchFont(H,W = %d,%d; Weight = %d; Italic = %d; FaceName = '%s'\n",
159 font->lfHeight, font->lfWidth, font->lfWeight, font->lfItalic, font->lfFaceName);
160 weight = (font->lfWeight > 550) ? "bold" : "medium";
161 slant = font->lfItalic ? 'i' : 'r';
162 if (font->lfHeight == -1)
163 height = 0;
164 else
165 height = font->lfHeight * dc->w.VportExtX / dc->w.WndExtX;
166 if (height == 0) height = 120; /* Default height = 12 */
167 else if (height < 0)
169 /* If height is negative, it means the height of the characters */
170 /* *without* the internal leading. So we adjust it a bit to */
171 /* compensate. 5/4 seems to give good results for small fonts. */
173 * J.M.: This causes wrong font size for bigger fonts e.g. in Winword & Write
174 height = 10 * (-height * 9 / 8);
175 * may be we have to use an non linear function
177 /* assume internal leading is 2 pixels. Else small fonts will become
178 * very small. */
179 height = (height-2) * -10;
181 else height *= 10;
182 width = 10 * (font->lfWidth * dc->w.VportExtY / dc->w.WndExtY);
183 if (width < 0) {
184 dprintf_font( stddeb, "FONT_MatchFont: negative width %d(%d)\n",
185 width, font->lfWidth );
186 width = -width;
189 spacing = (font->lfPitchAndFamily & FIXED_PITCH) ? 'm' :
190 (font->lfPitchAndFamily & VARIABLE_PITCH) ? 'p' : '*';
193 charset = (font->lfCharSet == ANSI_CHARSET) ? "iso8859-1" : "*-*";
194 if (*font->lfFaceName) {
195 family = FONT_ChkX11Family(font->lfFaceName);
196 /*--do _not_ translate if lfFaceName is family from X11 A.K.*/
197 if (!family)
198 family = FONT_TranslateName( font->lfFaceName );
199 /* FIX ME: I don't if that's correct but it works J.M. */
200 spacing = '*';
202 else switch(font->lfPitchAndFamily & 0xf0)
204 case FF_ROMAN:
205 family = FONT_TranslateName( "roman" );
206 break;
207 case FF_SWISS:
208 family = FONT_TranslateName( "swiss" );
209 break;
210 case FF_MODERN:
211 family = FONT_TranslateName( "modern" );
212 break;
213 case FF_SCRIPT:
214 family = FONT_TranslateName( "script" );
215 break;
216 case FF_DECORATIVE:
217 family = FONT_TranslateName( "decorative" );
218 break;
219 default:
220 family = "*-*";
221 break;
223 oldheight = height;
224 oldspacing = spacing;
225 while (TRUE) {
226 /* Width==0 seems not to be a valid wildcard on SGI's, using * instead */
227 if ( width == 0 )
228 sprintf( pattern, "-%s-%s-%c-normal-*-*-%d-*-*-%c-*-%s",
229 family, weight, slant, height, spacing, charset);
230 else
231 sprintf( pattern, "-%s-%s-%c-normal-*-*-%d-*-*-%c-%d-%s",
232 family, weight, slant, height, spacing, width, charset);
233 dprintf_font(stddeb, "FONT_MatchFont: '%s'\n", pattern );
234 names = XListFonts( display, pattern, 1, &count );
235 if (count > 0) break;
236 if (spacing == 'm') /* try 'c' if no 'm' found */ {
238 spacing = 'c';
239 continue;
240 } else if (spacing == 'p') /* try '*' if no 'p' found */ {
241 spacing = '*';
242 continue;
244 spacing = oldspacing;
245 height -= 10;
246 if (height < 10) {
247 if (slant == 'i') {
248 /* try oblique if no italic font */
249 slant = 'o';
250 height = oldheight;
251 continue;
253 if (spacing == 'm' && strcmp(family, "*-*") != 0) {
254 /* If a fixed spacing font could not be found, ignore
255 * the family */
256 family = "*-*";
257 height = oldheight;
258 continue;
260 fprintf(stderr, "FONT_MatchFont(%s) : returning NULL\n", pattern);
261 return NULL;
264 dprintf_font(stddeb," Found '%s'\n", *names );
265 if (!*font->lfFaceName)
266 ParseFontParms(*names, 2, font->lfFaceName , LF_FACESIZE-1);
267 /* we need a font name for function GetTextFace() even if there isn't one ;-) */
268 AnsiUpper(font->lfFaceName);
270 fontStruct = XLoadQueryFont( display, *names );
271 XFreeFontNames( names );
272 return fontStruct;
276 /***********************************************************************
277 * FONT_GetMetrics
279 void FONT_GetMetrics( LOGFONT16 * logfont, XFontStruct * xfont,
280 TEXTMETRIC16 * metrics )
282 int average, i, count;
283 unsigned long prop;
285 metrics->tmAscent = xfont->ascent;
286 metrics->tmDescent = xfont->descent;
287 metrics->tmHeight = xfont->ascent + xfont->descent;
289 metrics->tmInternalLeading = 0;
290 if (XGetFontProperty( xfont, XA_X_HEIGHT, &prop ))
291 metrics->tmInternalLeading = xfont->ascent - (short)prop;
292 metrics->tmExternalLeading = 0;
293 metrics->tmMaxCharWidth = xfont->max_bounds.width;
294 metrics->tmWeight = logfont->lfWeight;
295 metrics->tmItalic = logfont->lfItalic;
296 metrics->tmUnderlined = logfont->lfUnderline;
297 metrics->tmStruckOut = logfont->lfStrikeOut;
298 metrics->tmFirstChar = xfont->min_char_or_byte2;
299 metrics->tmLastChar = xfont->max_char_or_byte2;
300 metrics->tmDefaultChar = xfont->default_char;
301 metrics->tmBreakChar = ' ';
302 metrics->tmCharSet = logfont->lfCharSet;
303 metrics->tmOverhang = 0;
304 metrics->tmDigitizedAspectX = 1;
305 metrics->tmDigitizedAspectY = 1;
306 metrics->tmPitchAndFamily = (logfont->lfPitchAndFamily&0xf0)|TMPF_DEVICE;
307 if (logfont->lfPitchAndFamily & FIXED_PITCH)
308 metrics->tmPitchAndFamily |= TMPF_FIXED_PITCH;
310 if (!xfont->per_char) average = metrics->tmMaxCharWidth;
311 else
313 XCharStruct * charPtr = xfont->per_char;
314 average = count = 0;
315 for (i = metrics->tmFirstChar; i <= metrics->tmLastChar; i++)
317 if (!CI_NONEXISTCHAR( charPtr ))
319 average += charPtr->width;
320 count++;
322 charPtr++;
324 if (count) average = (average + count/2) / count;
326 metrics->tmAveCharWidth = average;
329 /***********************************************************************
330 * GetGlyphOutLine (GDI.309)
332 DWORD GetGlyphOutLine(HDC hdc, UINT uChar, UINT fuFormat, LPGLYPHMETRICS lpgm,
333 DWORD cbBuffer, LPSTR lpBuffer, LPMAT2 lpmat2)
335 fprintf( stdnimp,"GetGlyphOutLine(%04x, '%c', %04x, %p, %ld, %p, %p) // - empty stub!\n",
336 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
337 return (DWORD)-1; /* failure */
341 /***********************************************************************
342 * CreateScalableFontResource (GDI.310)
344 BOOL CreateScalableFontResource( UINT fHidden,LPSTR lpszResourceFile,
345 LPSTR lpszFontFile, LPSTR lpszCurrentPath )
347 /* fHidden=1 - only visible for the calling app, read-only, not
348 * enumbered with EnumFonts/EnumFontFamilies
349 * lpszCurrentPath can be NULL
351 fprintf(stdnimp,"CreateScalableFontResource(%d,%s,%s,%s) // empty stub!\n",
352 fHidden, lpszResourceFile, lpszFontFile, lpszCurrentPath );
353 return FALSE; /* create failed */
357 /***********************************************************************
358 * CreateFontIndirect16 (GDI.57)
360 HFONT16 CreateFontIndirect16( const LOGFONT16 *font )
362 FONTOBJ * fontPtr;
363 HFONT16 hfont;
365 if (!font)
367 fprintf(stderr,"CreateFontIndirect: font is NULL : returning NULL\n");
368 return 0;
370 hfont = GDI_AllocObject( sizeof(FONTOBJ), FONT_MAGIC );
371 if (!hfont) return 0;
372 fontPtr = (FONTOBJ *) GDI_HEAP_LIN_ADDR( hfont );
373 memcpy( &fontPtr->logfont, font, sizeof(LOGFONT16) );
374 AnsiLower( fontPtr->logfont.lfFaceName );
375 dprintf_font(stddeb,"CreateFontIndirect(%p (%d,%d)); return %04x\n",
376 font, font->lfHeight, font->lfWidth, hfont);
377 return hfont;
381 /***********************************************************************
382 * CreateFontIndirect32A (GDI32.44)
384 HFONT32 CreateFontIndirect32A( const LOGFONT32A *font )
386 LOGFONT16 font16;
388 font16.lfHeight = (INT16)font->lfHeight;
389 font16.lfWidth = (INT16)font->lfWidth;
390 font16.lfEscapement = (INT16)font->lfEscapement;
391 font16.lfOrientation = (INT16)font->lfOrientation;
392 font16.lfWeight = (INT16)font->lfWeight;
393 font16.lfItalic = font->lfItalic;
394 font16.lfUnderline = font->lfUnderline;
395 font16.lfStrikeOut = font->lfStrikeOut;
396 font16.lfCharSet = font->lfCharSet;
397 font16.lfOutPrecision = font->lfOutPrecision;
398 font16.lfClipPrecision = font->lfClipPrecision;
399 font16.lfQuality = font->lfQuality;
400 font16.lfPitchAndFamily = font->lfPitchAndFamily;
401 lstrcpyn32A( font16.lfFaceName, font->lfFaceName, LF_FACESIZE );
402 return CreateFontIndirect16( &font16 );
406 /***********************************************************************
407 * CreateFontIndirect32W (GDI32.45)
409 HFONT32 CreateFontIndirect32W( const LOGFONT32W *font )
411 LOGFONT16 font16;
413 font16.lfHeight = (INT16)font->lfHeight;
414 font16.lfWidth = (INT16)font->lfWidth;
415 font16.lfEscapement = (INT16)font->lfEscapement;
416 font16.lfOrientation = (INT16)font->lfOrientation;
417 font16.lfWeight = (INT16)font->lfWeight;
418 font16.lfItalic = font->lfItalic;
419 font16.lfUnderline = font->lfUnderline;
420 font16.lfStrikeOut = font->lfStrikeOut;
421 font16.lfCharSet = font->lfCharSet;
422 font16.lfOutPrecision = font->lfOutPrecision;
423 font16.lfClipPrecision = font->lfClipPrecision;
424 font16.lfQuality = font->lfQuality;
425 font16.lfPitchAndFamily = font->lfPitchAndFamily;
426 lstrcpynWtoA( font16.lfFaceName, font->lfFaceName, LF_FACESIZE );
427 return CreateFontIndirect16( &font16 );
431 /***********************************************************************
432 * CreateFont16 (GDI.56)
434 HFONT16 CreateFont16( INT16 height, INT16 width, INT16 esc, INT16 orient,
435 INT16 weight, BYTE italic, BYTE underline,
436 BYTE strikeout, BYTE charset, BYTE outpres,
437 BYTE clippres, BYTE quality, BYTE pitch, LPCSTR name )
439 LOGFONT16 logfont = {height, width, esc, orient, weight, italic, underline,
440 strikeout, charset, outpres, clippres, quality, pitch, };
441 dprintf_font(stddeb,"CreateFont16(%d,%d)\n", height, width);
442 if (name) lstrcpyn32A(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
443 else logfont.lfFaceName[0] = '\0';
444 return CreateFontIndirect16( &logfont );
449 /*************************************************************************
450 * CreateFont32A (GDI32.43)
452 HFONT32 CreateFont32A( INT32 height, INT32 width, INT32 esc, INT32 orient,
453 INT32 weight, DWORD italic, DWORD underline,
454 DWORD strikeout, DWORD charset, DWORD outpres,
455 DWORD clippres, DWORD quality, DWORD pitch, LPCSTR name)
457 return (HFONT32)CreateFont16( height, width, esc, orient, weight, italic,
458 underline, strikeout, charset, outpres,
459 clippres, quality, pitch, name );
463 /*************************************************************************
464 * CreateFont32W (GDI32.46)
466 HFONT32 CreateFont32W( INT32 height, INT32 width, INT32 esc, INT32 orient,
467 INT32 weight, DWORD italic, DWORD underline,
468 DWORD strikeout, DWORD charset, DWORD outpres,
469 DWORD clippres, DWORD quality, DWORD pitch,
470 LPCWSTR name )
472 LPSTR namea = name ? STRING32_DupUniToAnsi(name) : NULL;
473 HFONT32 ret = (HFONT32)CreateFont16( height, width, esc, orient, weight,
474 italic, underline, strikeout, charset,
475 outpres, clippres, quality, pitch,
476 namea );
477 free(namea);
478 return ret;
482 /***********************************************************************
483 * FONT_GetObject
485 int FONT_GetObject( FONTOBJ * font, int count, LPSTR buffer )
487 if (count > sizeof(LOGFONT16)) count = sizeof(LOGFONT16);
488 memcpy( buffer, &font->logfont, count );
489 return count;
493 /***********************************************************************
494 * FONT_SelectObject
496 HFONT FONT_SelectObject( DC * dc, HFONT hfont, FONTOBJ * font )
498 static X_PHYSFONT stockFonts[LAST_STOCK_FONT-FIRST_STOCK_FONT+1];
500 static struct {
501 HFONT id;
502 LOGFONT16 logfont;
503 int access;
504 int used;
505 X_PHYSFONT cacheFont; } cacheFonts[FONTCACHE], *cacheFontsMin;
506 int i;
508 X_PHYSFONT * stockPtr;
509 HFONT prevHandle = dc->w.hFont;
510 XFontStruct * fontStruct;
511 dprintf_font(stddeb,"FONT_SelectObject(%p, %04x, %p)\n", dc, hfont, font);
513 #if 0 /* From the code in SelectObject, this can not happen */
514 /* Load font if necessary */
515 if (!font)
517 HFONT hnewfont;
519 hnewfont = CreateFont16(10, 7, 0, 0, FW_DONTCARE,
520 FALSE, FALSE, FALSE, DEFAULT_CHARSET, 0, 0,
521 DEFAULT_QUALITY, FF_DONTCARE, "*" );
522 font = (FONTOBJ *) GDI_HEAP_LIN_ADDR( hnewfont );
524 #endif
526 if (dc->header.wMagic == METAFILE_DC_MAGIC)
527 if (MF_CreateFontIndirect(dc, hfont, &(font->logfont)))
528 return prevHandle;
529 else
530 return 0;
532 if ((hfont >= FIRST_STOCK_FONT) && (hfont <= LAST_STOCK_FONT))
533 stockPtr = &stockFonts[hfont - FIRST_STOCK_FONT];
534 else {
535 stockPtr = NULL;
537 * Ok, It's not a stock font but
538 * may be it's cached in dynamic cache
540 for(i=0; i<FONTCACHE; i++) /* search for same handle */
541 if (cacheFonts[i].id==hfont) { /* Got the handle */
543 * Check if Handle matches the font
545 if(memcmp(&cacheFonts[i].logfont,&(font->logfont), sizeof(LOGFONT16))) {
546 /* No: remove handle id from dynamic font cache */
547 cacheFonts[i].access=0;
548 cacheFonts[i].used=0;
549 cacheFonts[i].id=0;
550 /* may be there is an unused handle which contains the font */
551 for(i=0; i<FONTCACHE; i++) {
552 if((cacheFonts[i].used == 0) &&
553 (memcmp(&cacheFonts[i].logfont,&(font->logfont), sizeof(LOGFONT16)))== 0) {
554 /* got it load from cache and set new handle id */
555 stockPtr = &cacheFonts[i].cacheFont;
556 cacheFonts[i].access=1;
557 cacheFonts[i].used=1;
558 cacheFonts[i].id=hfont;
559 dprintf_font(stddeb,"FONT_SelectObject: got font from unused handle\n");
560 break;
565 else {
566 /* Yes: load from dynamic font cache */
567 stockPtr = &cacheFonts[i].cacheFont;
568 cacheFonts[i].access++;
569 cacheFonts[i].used++;
571 break;
574 if (!stockPtr || !stockPtr->fstruct)
576 if (!(fontStruct = FONT_MatchFont( &font->logfont, dc )))
578 /* If it is not a stock font, we can simply return 0 */
579 if (!stockPtr) return 0;
580 /* Otherwise we must try to find a substitute */
581 dprintf_font(stddeb,"Loading font 'fixed' for %04x\n", hfont );
582 font->logfont.lfPitchAndFamily &= ~VARIABLE_PITCH;
583 font->logfont.lfPitchAndFamily |= FIXED_PITCH;
584 fontStruct = XLoadQueryFont( display, "fixed" );
585 if (!fontStruct)
587 fprintf( stderr, "No system font could be found. Please check your font path.\n" );
588 exit( 1 );
592 else
594 fontStruct = stockPtr->fstruct;
595 dprintf_font(stddeb,
596 "FONT_SelectObject: Loaded font from cache %04x %p\n",
597 hfont, fontStruct );
600 /* Unuse previous font */
601 for (i=0; i < FONTCACHE; i++) {
602 if (cacheFonts[i].id == prevHandle) {
603 if(cacheFonts[i].used == 0)
604 fprintf(stderr, "Trying to decrement a use count of 0.\n");
605 else
606 cacheFonts[i].used--;
610 /* Store font */
611 dc->w.hFont = hfont;
612 if (stockPtr)
614 if (!stockPtr->fstruct)
616 stockPtr->fstruct = fontStruct;
617 FONT_GetMetrics( &font->logfont, fontStruct, &stockPtr->metrics );
619 memcpy( &dc->u.x.font, stockPtr, sizeof(*stockPtr) );
621 else
624 * Check in cacheFont
626 cacheFontsMin=NULL;
627 for (i=0; i < FONTCACHE; i++) {
628 if (cacheFonts[i].used==0)
629 if ((!cacheFontsMin) || ((cacheFontsMin) && (cacheFontsMin->access > cacheFonts[i].access)))
630 cacheFontsMin=&cacheFonts[i];
632 if (!cacheFontsMin) {
633 fprintf(stderr,"No unused font cache entry !!!!\n" );
634 return prevHandle;
636 if (cacheFontsMin->id!=0) {
637 dprintf_font(stddeb,
638 "FONT_SelectObject: Freeing %04x \n",cacheFontsMin->id );
639 XFreeFont( display, cacheFontsMin->cacheFont.fstruct );
641 cacheFontsMin->cacheFont.fstruct = fontStruct;
642 FONT_GetMetrics( &font->logfont, fontStruct, &cacheFontsMin->cacheFont.metrics );
643 cacheFontsMin->access=1;
644 cacheFontsMin->used=1;
645 cacheFontsMin->id=hfont;
646 memcpy( &dc->u.x.font, &(cacheFontsMin->cacheFont), sizeof(cacheFontsMin->cacheFont) );
647 memcpy(&cacheFontsMin->logfont,&(font->logfont), sizeof(LOGFONT16));
650 return prevHandle;
654 /***********************************************************************
655 * GetTextCharacterExtra (GDI.89)
657 short GetTextCharacterExtra( HDC hdc )
659 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
660 if (!dc) return 0;
661 return abs( (dc->w.charExtra * dc->w.WndExtX + dc->w.VportExtX / 2)
662 / dc->w.VportExtX );
666 /***********************************************************************
667 * SetTextCharacterExtra (GDI.8)
669 short SetTextCharacterExtra( HDC hdc, short extra )
671 short prev;
672 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
673 if (!dc) return 0;
674 extra = (extra * dc->w.VportExtX + dc->w.WndExtX / 2) / dc->w.WndExtX;
675 prev = dc->w.charExtra;
676 dc->w.charExtra = abs(extra);
677 return (prev * dc->w.WndExtX + dc->w.VportExtX / 2) / dc->w.VportExtX;
681 /***********************************************************************
682 * SetTextJustification (GDI.10)
684 short SetTextJustification( HDC hdc, short extra, short breaks )
686 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
687 if (!dc) return 0;
689 extra = abs((extra * dc->w.VportExtX + dc->w.WndExtX / 2) / dc->w.WndExtX);
690 if (!extra) breaks = 0;
691 dc->w.breakTotalExtra = extra;
692 dc->w.breakCount = breaks;
693 if (breaks)
695 dc->w.breakExtra = extra / breaks;
696 dc->w.breakRem = extra - (dc->w.breakCount * dc->w.breakExtra);
698 else
700 dc->w.breakExtra = 0;
701 dc->w.breakRem = 0;
703 return 1;
707 /***********************************************************************
708 * GetTextFace (GDI.92)
710 INT GetTextFace( HDC hdc, INT count, LPSTR name )
712 FONTOBJ *font;
714 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
715 if (!dc) return 0;
716 if (!(font = (FONTOBJ *) GDI_GetObjPtr( dc->w.hFont, FONT_MAGIC )))
717 return 0;
718 lstrcpyn32A( name, font->logfont.lfFaceName, count );
719 return strlen(name);
723 /***********************************************************************
724 * GetTextExtent (GDI.91)
726 DWORD GetTextExtent( HDC hdc, LPCSTR str, short count )
728 SIZE16 size;
729 if (!GetTextExtentPoint16( hdc, str, count, &size )) return 0;
730 return MAKELONG( size.cx, size.cy );
734 /***********************************************************************
735 * GetTextExtentPoint16 (GDI.471)
737 BOOL16 GetTextExtentPoint16( HDC16 hdc, LPCSTR str, INT16 count, LPSIZE16 size)
739 SIZE32 size32;
740 BOOL32 ret = GetTextExtentPoint32A( hdc, str, count, &size32 );
741 CONV_SIZE32TO16( &size32, size );
742 return (BOOL16)ret;
746 /***********************************************************************
747 * GetTextExtentPoint32A (GDI32.232)
749 BOOL32 GetTextExtentPoint32A( HDC32 hdc, LPCSTR str, INT32 count,
750 LPSIZE32 size )
752 int dir, ascent, descent;
753 XCharStruct info;
755 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
756 if (!dc) return FALSE;
757 XTextExtents( dc->u.x.font.fstruct, str, count, &dir,
758 &ascent, &descent, &info );
759 size->cx = abs((info.width + dc->w.breakRem + count * dc->w.charExtra)
760 * dc->w.WndExtX / dc->w.VportExtX);
761 size->cy = abs((dc->u.x.font.fstruct->ascent+dc->u.x.font.fstruct->descent)
762 * dc->w.WndExtY / dc->w.VportExtY);
764 dprintf_font(stddeb,"GetTextExtentPoint(%08x '%*.*s' %d %p): returning %d,%d\n",
765 hdc, count, count, str, count, size, size->cx, size->cy );
766 return TRUE;
770 /***********************************************************************
771 * GetTextExtentPoint32W (GDI32.233)
773 BOOL32 GetTextExtentPoint32W( HDC32 hdc, LPCWSTR str, INT32 count,
774 LPSIZE32 size )
776 char *p = STRING32_DupUniToAnsi( str );
777 BOOL32 ret = GetTextExtentPoint32A( hdc, p, count, size );
778 free( p );
779 return ret;
783 /***********************************************************************
784 * GetTextMetrics16 (GDI.93)
786 BOOL16 GetTextMetrics16( HDC16 hdc, TEXTMETRIC16 *metrics )
788 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
789 if (!dc) return FALSE;
790 memcpy( metrics, &dc->u.x.font.metrics, sizeof(*metrics) );
792 metrics->tmAscent = abs( metrics->tmAscent
793 * dc->w.WndExtY / dc->w.VportExtY );
794 metrics->tmDescent = abs( metrics->tmDescent
795 * dc->w.WndExtY / dc->w.VportExtY );
796 metrics->tmHeight = metrics->tmAscent + metrics->tmDescent;
797 metrics->tmInternalLeading = abs( metrics->tmInternalLeading
798 * dc->w.WndExtY / dc->w.VportExtY );
799 metrics->tmExternalLeading = abs( metrics->tmExternalLeading
800 * dc->w.WndExtY / dc->w.VportExtY );
801 metrics->tmMaxCharWidth = abs( metrics->tmMaxCharWidth
802 * dc->w.WndExtX / dc->w.VportExtX );
803 metrics->tmAveCharWidth = abs( metrics->tmAveCharWidth
804 * dc->w.WndExtX / dc->w.VportExtX );
806 dprintf_font(stdnimp,"text metrics:\n
807 InternalLeading = %i
808 ExternalLeading = %i
809 MaxCharWidth = %i
810 Weight = %i
811 Italic = %i
812 Underlined = %i
813 StruckOut = %i
814 FirstChar = %i
815 LastChar = %i
816 DefaultChar = %i
817 BreakChar = %i
818 CharSet = %i
819 Overhang = %i
820 DigitizedAspectX = %i
821 DigitizedAspectY = %i
822 AveCharWidth = %i
823 MaxCharWidth = %i
824 Ascent = %i
825 Descent = %i
826 Height = %i\n",
827 metrics->tmInternalLeading,
828 metrics->tmExternalLeading,
829 metrics->tmMaxCharWidth,
830 metrics->tmWeight,
831 metrics->tmItalic,
832 metrics->tmUnderlined,
833 metrics->tmStruckOut,
834 metrics->tmFirstChar,
835 metrics->tmLastChar,
836 metrics->tmDefaultChar,
837 metrics->tmBreakChar,
838 metrics->tmCharSet,
839 metrics->tmOverhang,
840 metrics->tmDigitizedAspectX,
841 metrics->tmDigitizedAspectY,
842 metrics->tmAveCharWidth,
843 metrics->tmMaxCharWidth,
844 metrics->tmAscent,
845 metrics->tmDescent,
846 metrics->tmHeight);
848 return TRUE;
852 /***********************************************************************
853 * GetTextMetrics32A (GDI32.236)
855 BOOL32 GetTextMetrics32A( HDC32 hdc, TEXTMETRIC32A *metrics )
857 TEXTMETRIC16 tm;
858 if (!GetTextMetrics16( (HDC16)hdc, &tm )) return FALSE;
859 metrics->tmHeight = tm.tmHeight;
860 metrics->tmAscent = tm.tmAscent;
861 metrics->tmDescent = tm.tmDescent;
862 metrics->tmInternalLeading = tm.tmInternalLeading;
863 metrics->tmExternalLeading = tm.tmExternalLeading;
864 metrics->tmAveCharWidth = tm.tmAveCharWidth;
865 metrics->tmMaxCharWidth = tm.tmMaxCharWidth;
866 metrics->tmWeight = tm.tmWeight;
867 metrics->tmOverhang = tm.tmOverhang;
868 metrics->tmDigitizedAspectX = tm.tmDigitizedAspectX;
869 metrics->tmDigitizedAspectY = tm.tmDigitizedAspectY;
870 metrics->tmFirstChar = tm.tmFirstChar;
871 metrics->tmLastChar = tm.tmLastChar;
872 metrics->tmDefaultChar = tm.tmDefaultChar;
873 metrics->tmBreakChar = tm.tmBreakChar;
874 metrics->tmItalic = tm.tmItalic;
875 metrics->tmUnderlined = tm.tmUnderlined;
876 metrics->tmStruckOut = tm.tmStruckOut;
877 metrics->tmPitchAndFamily = tm.tmPitchAndFamily;
878 metrics->tmCharSet = tm.tmCharSet;
879 return TRUE;
883 /***********************************************************************
884 * GetTextMetrics32W (GDI32.237)
886 BOOL32 GetTextMetrics32W( HDC32 hdc, TEXTMETRIC32W *metrics )
888 TEXTMETRIC16 tm;
889 if (!GetTextMetrics16( (HDC16)hdc, &tm )) return FALSE;
890 metrics->tmHeight = tm.tmHeight;
891 metrics->tmAscent = tm.tmAscent;
892 metrics->tmDescent = tm.tmDescent;
893 metrics->tmInternalLeading = tm.tmInternalLeading;
894 metrics->tmExternalLeading = tm.tmExternalLeading;
895 metrics->tmAveCharWidth = tm.tmAveCharWidth;
896 metrics->tmMaxCharWidth = tm.tmMaxCharWidth;
897 metrics->tmWeight = tm.tmWeight;
898 metrics->tmOverhang = tm.tmOverhang;
899 metrics->tmDigitizedAspectX = tm.tmDigitizedAspectX;
900 metrics->tmDigitizedAspectY = tm.tmDigitizedAspectY;
901 metrics->tmFirstChar = tm.tmFirstChar;
902 metrics->tmLastChar = tm.tmLastChar;
903 metrics->tmDefaultChar = tm.tmDefaultChar;
904 metrics->tmBreakChar = tm.tmBreakChar;
905 metrics->tmItalic = tm.tmItalic;
906 metrics->tmUnderlined = tm.tmUnderlined;
907 metrics->tmStruckOut = tm.tmStruckOut;
908 metrics->tmPitchAndFamily = tm.tmPitchAndFamily;
909 metrics->tmCharSet = tm.tmCharSet;
910 return TRUE;
914 /***********************************************************************
915 * SetMapperFlags (GDI.349)
917 DWORD SetMapperFlags(HDC hDC, DWORD dwFlag)
919 dprintf_font(stdnimp,"SetmapperFlags(%04x, %08lX) // Empty Stub !\n",
920 hDC, dwFlag);
921 return 0L;
925 /***********************************************************************
926 * GetCharABCWidths (GDI.307)
928 BOOL GetCharABCWidths(HDC hdc, UINT wFirstChar, UINT wLastChar, LPABC16 lpABC)
931 /* No TrueType fonts in Wine so far */
933 fprintf(stdnimp,"STUB: GetCharABCWidths(%04x,%04x,%04x,%08x)\n",
934 hdc,wFirstChar,wLastChar,(unsigned)lpABC);
936 return FALSE;
940 /***********************************************************************
941 * GetCharWidth (GDI.350)
943 BOOL GetCharWidth(HDC hdc, WORD wFirstChar, WORD wLastChar, LPINT16 lpBuffer)
945 int i, j;
946 XFontStruct *xfont;
947 XCharStruct *cs, *def;
949 DC *dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC);
950 if (!dc) return FALSE;
951 xfont = dc->u.x.font.fstruct;
953 /* fixed font? */
954 if (xfont->per_char == NULL)
956 for (i = wFirstChar, j = 0; i <= wLastChar; i++, j++)
957 *(lpBuffer + j) = xfont->max_bounds.width;
958 return TRUE;
961 CI_GET_DEFAULT_INFO(xfont, def);
963 for (i = wFirstChar, j = 0; i <= wLastChar; i++, j++)
965 CI_GET_CHAR_INFO(xfont, i, def, cs);
966 *(lpBuffer + j) = cs ? cs->width : xfont->max_bounds.width;
967 if (*(lpBuffer + j) < 0)
968 *(lpBuffer + j) = 0;
970 return TRUE;
974 /***********************************************************************
975 * AddFontResource (GDI.119)
977 INT AddFontResource( LPCSTR str )
979 fprintf( stdnimp, "STUB: AddFontResource('%s')\n", str );
980 return 1;
984 /***********************************************************************
985 * RemoveFontResource (GDI.136)
987 BOOL RemoveFontResource( LPSTR str )
989 fprintf( stdnimp, "STUB: RemoveFontResource('%s')\n", str );
990 return TRUE;
994 /*************************************************************************
995 * ParseFontParms [internal]
997 int ParseFontParms(LPSTR lpFont, WORD wParmsNo, LPSTR lpRetStr, WORD wMaxSiz)
999 int i;
1000 if (lpFont == NULL) return 0;
1001 if (lpRetStr == NULL) return 0;
1002 for (i = 0; (*lpFont != '\0' && i != wParmsNo); ) {
1003 if (*lpFont == '-') i++;
1004 lpFont++;
1006 if (i == wParmsNo) {
1007 if (*lpFont == '-') lpFont++;
1008 wMaxSiz--;
1009 for (i = 0; (*lpFont != '\0' && *lpFont != '-' && i < wMaxSiz); i++)
1010 *(lpRetStr + i) = *lpFont++;
1011 *(lpRetStr + i) = '\0';
1012 return i;
1014 else
1015 lpRetStr[0] = '\0';
1016 return 0;
1020 /*************************************************************************
1021 * InitFontsList [internal]
1024 static int logfcmp(const void *a,const void *b)
1026 return strcmp( (*(LPLOGFONT16 *)a)->lfFaceName,
1027 (*(LPLOGFONT16 *)b)->lfFaceName );
1030 void InitFontsList(void)
1032 char str[32];
1033 char pattern[100];
1034 char *family, *weight, *charset;
1035 char **names;
1036 char slant, spacing;
1037 int i, count;
1038 LPLOGFONT16 lpNewFont;
1040 dprintf_font(stddeb,"InitFontsList !\n");
1042 weight = "medium";
1043 slant = 'r';
1044 spacing = '*';
1045 charset = "*";
1046 family = "*-*";
1048 sprintf( pattern, "-%s-%s-%c-normal-*-*-*-*-*-%c-*-%s",
1049 family, weight, slant, spacing, charset);
1050 names = XListFonts( display, pattern, MAX_FONTS, &count );
1051 dprintf_font(stddeb,"InitFontsList // count=%d \n", count);
1053 lpNewFont = malloc((sizeof(LOGFONT16)+LF_FACESIZE)*count);
1054 if (lpNewFont == NULL) {
1055 dprintf_font(stddeb,
1056 "InitFontsList // Error alloc new font structure !\n");
1057 XFreeFontNames(names);
1058 return;
1061 for (i = 0; i < count; i++) {
1062 dprintf_font(stddeb,"InitFontsList // names[%d]='%s' \n", i, names[i]);
1064 ParseFontParms(names[i], 2, str, sizeof(str));
1065 #if 0
1066 /* not necessary because new function FONT_ChkX11Family() */
1067 if (strcmp(str, "fixed") == 0) strcat(str, "sys");
1068 #endif
1069 AnsiUpper(str);
1070 strcpy(lpNewFont->lfFaceName, str);
1071 ParseFontParms(names[i], 8, str, sizeof(str));
1072 lpNewFont->lfHeight = atoi(str) / 10;
1073 ParseFontParms(names[i], 12, str, sizeof(str));
1074 lpNewFont->lfWidth = atoi(str) / 10;
1075 lpNewFont->lfEscapement = 0;
1076 lpNewFont->lfOrientation = 0;
1077 lpNewFont->lfWeight = FW_REGULAR;
1078 lpNewFont->lfItalic = 0;
1079 lpNewFont->lfUnderline = 0;
1080 lpNewFont->lfStrikeOut = 0;
1081 ParseFontParms(names[i], 13, str, sizeof(str));
1082 if (strcmp(str, "iso8859") == 0) {
1083 lpNewFont->lfCharSet = ANSI_CHARSET;
1084 } else {
1085 lpNewFont->lfCharSet = OEM_CHARSET;
1087 lpNewFont->lfOutPrecision = OUT_DEFAULT_PRECIS;
1088 lpNewFont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
1089 lpNewFont->lfQuality = DEFAULT_QUALITY;
1090 ParseFontParms(names[i], 11, str, sizeof(str));
1091 switch(str[0]) {
1092 case 'p':
1093 lpNewFont->lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
1094 break;
1095 case 'm':
1096 case 'c':
1097 lpNewFont->lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
1098 break;
1099 default:
1100 lpNewFont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
1101 break;
1103 dprintf_font( stddeb,
1104 "InitFontsList // lpNewFont->lfHeight=%d\n",
1105 lpNewFont->lfHeight );
1106 dprintf_font( stddeb,
1107 "InitFontsList // lpNewFont->lfWidth=%d\n",
1108 lpNewFont->lfWidth );
1109 dprintf_font( stddeb,
1110 "InitFontsList // lfFaceName='%s'\n",
1111 lpNewFont->lfFaceName );
1112 lpLogFontList[i] = lpNewFont;
1113 lpNewFont = (LPLOGFONT16)
1114 ((char *)lpNewFont + sizeof(LOGFONT16)+LF_FACESIZE);
1116 lpLogFontList[i] = NULL;
1118 qsort(lpLogFontList,count,sizeof(*lpLogFontList),logfcmp);
1119 XFreeFontNames(names);
1123 /*************************************************************************
1124 * EnumFonts [GDI.70]
1126 INT EnumFonts(HDC hDC, LPCSTR lpFaceName, FONTENUMPROC16 lpEnumFunc, LPARAM lpData)
1128 HANDLE hLog;
1129 HANDLE hMet;
1130 HFONT hFont;
1131 HFONT hOldFont;
1132 LPLOGFONT16 lpLogFont;
1133 LPTEXTMETRIC16 lptm;
1134 LPSTR lpOldName;
1135 char FaceName[LF_FACESIZE];
1136 int nRet = 0;
1137 int i;
1139 dprintf_font(stddeb,"EnumFonts(%04x, %p='%s', %08lx, %08lx)\n",
1140 hDC, lpFaceName, lpFaceName, (LONG)lpEnumFunc, lpData);
1141 if (lpEnumFunc == 0) return 0;
1142 hLog = GDI_HEAP_ALLOC( sizeof(LOGFONT16) + LF_FACESIZE );
1143 lpLogFont = (LPLOGFONT16) GDI_HEAP_LIN_ADDR(hLog);
1144 if (lpLogFont == NULL) {
1145 fprintf(stderr,"EnumFonts // can't alloc LOGFONT struct !\n");
1146 return 0;
1148 hMet = GDI_HEAP_ALLOC( sizeof(TEXTMETRIC16) );
1149 lptm = (LPTEXTMETRIC16) GDI_HEAP_LIN_ADDR(hMet);
1150 if (lptm == NULL) {
1151 GDI_HEAP_FREE(hLog);
1152 fprintf(stderr, "EnumFonts // can't alloc TEXTMETRIC struct !\n");
1153 return 0;
1155 if (lpFaceName != NULL) {
1156 strcpy(FaceName, lpFaceName);
1157 AnsiUpper(FaceName);
1159 lpOldName = NULL;
1161 if (lpLogFontList[0] == NULL) InitFontsList();
1162 for(i = 0; lpLogFontList[i] != NULL; i++) {
1163 if (lpFaceName == NULL) {
1164 if (lpOldName != NULL) {
1165 if (strcmp(lpOldName,lpLogFontList[i]->lfFaceName) == 0) continue;
1167 lpOldName = lpLogFontList[i]->lfFaceName;
1168 } else {
1169 if (strcmp(FaceName, lpLogFontList[i]->lfFaceName) != 0) continue;
1171 dprintf_font(stddeb,"EnumFonts // enum '%s' !\n", lpLogFontList[i]->lfFaceName);
1172 dprintf_font(stddeb,"EnumFonts // %p !\n", lpLogFontList[i]);
1173 memcpy(lpLogFont, lpLogFontList[i], sizeof(LOGFONT16) + LF_FACESIZE);
1174 hFont = CreateFontIndirect16(lpLogFont);
1175 hOldFont = SelectObject(hDC, hFont);
1176 GetTextMetrics16(hDC, lptm);
1177 SelectObject(hDC, hOldFont);
1178 DeleteObject(hFont);
1179 dprintf_font(stddeb,"EnumFonts // i=%d lpLogFont=%p lptm=%p\n", i, lpLogFont, lptm);
1180 nRet = lpEnumFunc( GDI_HEAP_SEG_ADDR(hLog), GDI_HEAP_SEG_ADDR(hMet),
1181 0, (LONG)lpData );
1182 if (nRet == 0) {
1183 dprintf_font(stddeb,"EnumFonts // EnumEnd requested by application !\n");
1184 break;
1187 GDI_HEAP_FREE(hMet);
1188 GDI_HEAP_FREE(hLog);
1189 return nRet;
1193 /*************************************************************************
1194 * EnumFontFamilies [GDI.330]
1196 INT EnumFontFamilies(HDC hDC, LPCSTR lpszFamily, FONTENUMPROC16 lpEnumFunc, LPARAM lpData)
1198 HANDLE hLog;
1199 HANDLE hMet;
1200 HFONT hFont;
1201 HFONT hOldFont;
1202 LPENUMLOGFONT16 lpEnumLogFont;
1203 LPTEXTMETRIC16 lptm;
1204 LPSTR lpOldName;
1205 char FaceName[LF_FACESIZE];
1206 int nRet = 0;
1207 int i;
1209 dprintf_font(stddeb,"EnumFontFamilies(%04x, %p, %08lx, %08lx)\n",
1210 hDC, lpszFamily, (DWORD)lpEnumFunc, lpData);
1211 if (lpEnumFunc == 0) return 0;
1212 hLog = GDI_HEAP_ALLOC( sizeof(ENUMLOGFONT16) );
1213 lpEnumLogFont = (LPENUMLOGFONT16) GDI_HEAP_LIN_ADDR(hLog);
1214 if (lpEnumLogFont == NULL) {
1215 fprintf(stderr,"EnumFontFamilies // can't alloc LOGFONT struct !\n");
1216 return 0;
1218 hMet = GDI_HEAP_ALLOC( sizeof(TEXTMETRIC16) );
1219 lptm = (LPTEXTMETRIC16) GDI_HEAP_LIN_ADDR(hMet);
1220 if (lptm == NULL) {
1221 GDI_HEAP_FREE(hLog);
1222 fprintf(stderr,"EnumFontFamilies // can't alloc TEXTMETRIC struct !\n");
1223 return 0;
1225 lpOldName = NULL;
1226 if (lpszFamily != NULL) {
1227 strcpy(FaceName, lpszFamily);
1228 AnsiUpper(FaceName);
1230 if (lpLogFontList[0] == NULL) InitFontsList();
1231 for(i = 0; lpLogFontList[i] != NULL; i++) {
1232 if (lpszFamily == NULL) {
1233 if (lpOldName != NULL) {
1234 if (strcmp(lpOldName,lpLogFontList[i]->lfFaceName) == 0) continue;
1236 lpOldName = lpLogFontList[i]->lfFaceName;
1237 } else {
1238 if (strcmp(FaceName, lpLogFontList[i]->lfFaceName) != 0) continue;
1240 memcpy(lpEnumLogFont, lpLogFontList[i], sizeof(LOGFONT16));
1241 strcpy(lpEnumLogFont->elfFullName,"");
1242 strcpy(lpEnumLogFont->elfStyle,"");
1243 hFont = CreateFontIndirect16((LPLOGFONT16)lpEnumLogFont);
1244 hOldFont = SelectObject(hDC, hFont);
1245 GetTextMetrics16(hDC, lptm);
1246 SelectObject(hDC, hOldFont);
1247 DeleteObject(hFont);
1248 dprintf_font(stddeb, "EnumFontFamilies // i=%d lpLogFont=%p lptm=%p\n", i, lpEnumLogFont, lptm);
1250 nRet = lpEnumFunc( GDI_HEAP_SEG_ADDR(hLog), GDI_HEAP_SEG_ADDR(hMet),
1251 0, lpData );
1252 if (nRet == 0) {
1253 dprintf_font(stddeb,"EnumFontFamilies // EnumEnd requested by application !\n");
1254 break;
1257 GDI_HEAP_FREE(hMet);
1258 GDI_HEAP_FREE(hLog);
1259 return nRet;
1262 /*************************************************************************
1263 * GetRasterizerCaps [GDI.313]
1266 BOOL GetRasterizerCaps(LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
1268 /* This is not much more than a dummy */
1269 RASTERIZER_STATUS rs;
1271 rs.nSize = sizeof(rs);
1272 rs.wFlags = 0;
1273 rs.nLanguageID = 0;
1274 return True;
1277 /*************************************************************************
1278 * GetKerningPairs [GDI.332]
1280 int GetKerningPairs(HDC hDC,int cPairs,LPKERNINGPAIR16 lpKerningPairs)
1282 /* This has to be dealt with when proper font handling is in place
1284 * At this time kerning is ignored (set to 0)
1287 int i;
1288 fprintf(stdnimp,"GetKerningPairs: almost empty stub!\n");
1289 for (i = 0; i < cPairs; i++) lpKerningPairs[i].iKernAmount = 0;
1290 return 0;