Release 960611
[wine/multimedia.git] / objects / font.c
blob5cde9757a0d7f8c51b93ad2b5e6d8729d1280575
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 "callback.h"
19 #include "options.h"
20 #include "string32.h"
21 #include "xmalloc.h"
22 #include "stddebug.h"
23 #include "debug.h"
25 #define FONTCACHE 32 /* dynamic font cache size */
26 #define MAX_FONTS 256
27 static LPLOGFONT16 lpLogFontList[MAX_FONTS];
29 static int ParseFontParms(LPSTR lpFont, WORD wParmsNo, LPSTR lpRetStr, WORD wMaxSiz);
31 #define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
32 (((cs)->rbearing|(cs)->lbearing| \
33 (cs)->ascent|(cs)->descent) == 0))
35 /*
36 * CI_GET_CHAR_INFO - return the charinfo struct for the indicated 8bit
37 * character. If the character is in the column and exists, then return the
38 * appropriate metrics (note that fonts with common per-character metrics will
39 * return min_bounds). If none of these hold true, try again with the default
40 * char.
42 #define CI_GET_CHAR_INFO(fs,col,def,cs) \
43 { \
44 cs = def; \
45 if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
46 if (fs->per_char == NULL) { \
47 cs = &fs->min_bounds; \
48 } else { \
49 cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
50 if (CI_NONEXISTCHAR(cs)) cs = def; \
51 } \
52 } \
55 #define CI_GET_DEFAULT_INFO(fs,cs) \
56 CI_GET_CHAR_INFO(fs, fs->default_char, NULL, cs)
58 struct FontStructure {
59 char *window;
60 char *x11;
61 } FontNames[32];
62 int FontSize;
65 /***********************************************************************
66 * FONT_Init
68 BOOL FONT_Init( void )
70 char temp[1024];
71 LPSTR ptr;
72 int i;
74 if (PROFILE_GetWineIniString( "fonts", NULL, "*", temp, sizeof(temp) ) > 2 )
76 for( ptr = temp, i = 1; strlen(ptr) != 0; ptr += strlen(ptr) + 1 )
77 if( strcmp( ptr, "default" ) )
78 FontNames[i++].window = xstrdup( ptr );
79 FontSize = i;
81 for( i = 1; i < FontSize; i++ )
83 PROFILE_GetWineIniString( "fonts", FontNames[i].window, "*",
84 temp, sizeof(temp) );
85 FontNames[i].x11 = xstrdup( temp );
87 PROFILE_GetWineIniString( "fonts", "default", "*", temp, sizeof(temp) );
88 FontNames[0].x11 = xstrdup( temp );
90 } else {
91 FontNames[0].window = NULL; FontNames[0].x11 = "*-helvetica";
92 FontNames[1].window = "ms sans serif"; FontNames[1].x11 = "*-helvetica";
93 FontNames[2].window = "ms serif"; FontNames[2].x11 = "*-times";
94 FontNames[3].window = "fixedsys"; FontNames[3].x11 = "*-fixed";
95 FontNames[4].window = "arial"; FontNames[4].x11 = "*-helvetica";
96 FontNames[5].window = "helv"; FontNames[5].x11 = "*-helvetica";
97 FontNames[6].window = "roman"; FontNames[6].x11 = "*-times";
98 FontSize = 7;
100 return TRUE;
103 /***********************************************************************
104 * FONT_ChkX11Family
106 * returns a valid X11 equivalent if a Windows face name
107 * is like a X11 family - or NULL if translation is needed
109 static char *FONT_ChkX11Family(char *winFaceName )
111 static char x11fam[32+2]; /* will be returned */
112 int i;
114 for(i = 0; lpLogFontList[i] != NULL; i++)
115 if( !strcasecmp(winFaceName, lpLogFontList[i]->lfFaceName) )
117 strcpy(x11fam,"*-");
118 return strcat(x11fam,winFaceName);
120 return NULL; /* a FONT_TranslateName() call is needed */
125 /***********************************************************************
126 * FONT_TranslateName
128 * Translate a Windows face name to its X11 equivalent.
129 * This will probably have to be customizable.
131 static const char *FONT_TranslateName( char *winFaceName )
133 int i;
135 for (i = 1; i < FontSize; i ++)
136 if( !strcmp( winFaceName, FontNames[i].window ) ) {
137 dprintf_font(stddeb, "---- Mapped %s to %s\n", winFaceName, FontNames[i].x11 );
138 return FontNames[i].x11;
140 return FontNames[0].x11;
144 /***********************************************************************
145 * FONT_MatchFont
147 * Find a X font matching the logical font.
149 static XFontStruct * FONT_MatchFont( LOGFONT16 * font, DC * dc )
151 char pattern[100];
152 const char *family, *weight, *charset;
153 char **names;
154 char slant, oldspacing, spacing;
155 int width, height, oldheight, count;
156 XFontStruct * fontStruct;
158 dprintf_font(stddeb,
159 "FONT_MatchFont(H,W = %d,%d; Weight = %d; Italic = %d; FaceName = '%s'\n",
160 font->lfHeight, font->lfWidth, font->lfWeight, font->lfItalic, font->lfFaceName);
161 weight = (font->lfWeight > 550) ? "bold" : "medium";
162 slant = font->lfItalic ? 'i' : 'r';
163 if (font->lfHeight == -1)
164 height = 0;
165 else
166 height = font->lfHeight * dc->w.VportExtX / dc->w.WndExtX;
167 if (height == 0) height = 120; /* Default height = 12 */
168 else if (height < 0)
170 /* If height is negative, it means the height of the characters */
171 /* *without* the internal leading. So we adjust it a bit to */
172 /* compensate. 5/4 seems to give good results for small fonts. */
174 * J.M.: This causes wrong font size for bigger fonts e.g. in Winword & Write
175 height = 10 * (-height * 9 / 8);
176 * may be we have to use an non linear function
178 /* assume internal leading is 2 pixels. Else small fonts will become
179 * very small. */
180 height = (height-2) * -10;
182 else height *= 10;
183 width = 10 * (font->lfWidth * dc->w.VportExtY / dc->w.WndExtY);
184 if (width < 0) {
185 dprintf_font( stddeb, "FONT_MatchFont: negative width %d(%d)\n",
186 width, font->lfWidth );
187 width = -width;
190 spacing = (font->lfPitchAndFamily & FIXED_PITCH) ? 'm' :
191 (font->lfPitchAndFamily & VARIABLE_PITCH) ? 'p' : '*';
194 charset = (font->lfCharSet == ANSI_CHARSET) ? "iso8859-1" : "*-*";
195 if (*font->lfFaceName) {
196 family = FONT_ChkX11Family(font->lfFaceName);
197 /*--do _not_ translate if lfFaceName is family from X11 A.K.*/
198 if (!family)
199 family = FONT_TranslateName( font->lfFaceName );
200 /* FIX ME: I don't if that's correct but it works J.M. */
201 spacing = '*';
203 else switch(font->lfPitchAndFamily & 0xf0)
205 case FF_ROMAN:
206 family = FONT_TranslateName( "roman" );
207 break;
208 case FF_SWISS:
209 family = FONT_TranslateName( "swiss" );
210 break;
211 case FF_MODERN:
212 family = FONT_TranslateName( "modern" );
213 break;
214 case FF_SCRIPT:
215 family = FONT_TranslateName( "script" );
216 break;
217 case FF_DECORATIVE:
218 family = FONT_TranslateName( "decorative" );
219 break;
220 default:
221 family = "*-*";
222 break;
224 oldheight = height;
225 oldspacing = spacing;
226 while (TRUE) {
227 /* Width==0 seems not to be a valid wildcard on SGI's, using * instead */
228 if ( width == 0 )
229 sprintf( pattern, "-%s-%s-%c-normal-*-*-%d-*-*-%c-*-%s",
230 family, weight, slant, height, spacing, charset);
231 else
232 sprintf( pattern, "-%s-%s-%c-normal-*-*-%d-*-*-%c-%d-%s",
233 family, weight, slant, height, spacing, width, charset);
234 dprintf_font(stddeb, "FONT_MatchFont: '%s'\n", pattern );
235 names = XListFonts( display, pattern, 1, &count );
236 if (count > 0) break;
237 if (spacing == 'm') /* try 'c' if no 'm' found */ {
239 spacing = 'c';
240 continue;
241 } else if (spacing == 'p') /* try '*' if no 'p' found */ {
242 spacing = '*';
243 continue;
245 spacing = oldspacing;
246 height -= 10;
247 if (height < 10) {
248 if (slant == 'i') {
249 /* try oblique if no italic font */
250 slant = 'o';
251 height = oldheight;
252 continue;
254 if (spacing == 'm' && strcmp(family, "*-*") != 0) {
255 /* If a fixed spacing font could not be found, ignore
256 * the family */
257 family = "*-*";
258 height = oldheight;
259 continue;
261 fprintf(stderr, "FONT_MatchFont(%s) : returning NULL\n", pattern);
262 return NULL;
265 dprintf_font(stddeb," Found '%s'\n", *names );
266 if (!*font->lfFaceName)
267 ParseFontParms(*names, 2, font->lfFaceName , LF_FACESIZE-1);
268 /* we need a font name for function GetTextFace() even if there isn't one ;-) */
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 * CreateFontIndirect (GDI.57)
360 HFONT CreateFontIndirect( const LOGFONT16 * font )
362 FONTOBJ * fontPtr;
363 HFONT 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 * CreateFont (GDI.56)
384 HFONT CreateFont( INT height, INT width, INT esc, INT orient, INT weight,
385 BYTE italic, BYTE underline, BYTE strikeout, BYTE charset,
386 BYTE outpres, BYTE clippres, BYTE quality, BYTE pitch,
387 LPCSTR name )
389 LOGFONT16 logfont = {height, width, esc, orient, weight, italic, underline,
390 strikeout, charset, outpres, clippres, quality, pitch, };
391 dprintf_font(stddeb,"CreateFont(%d,%d)\n", height, width);
392 if (name)
394 strncpy( logfont.lfFaceName, name, LF_FACESIZE - 1 );
395 logfont.lfFaceName[LF_FACESIZE - 1] = '\0';
397 else logfont.lfFaceName[0] = '\0';
398 return CreateFontIndirect( &logfont );
402 /***********************************************************************
403 * FONT_GetObject
405 int FONT_GetObject( FONTOBJ * font, int count, LPSTR buffer )
407 if (count > sizeof(LOGFONT16)) count = sizeof(LOGFONT16);
408 memcpy( buffer, &font->logfont, count );
409 return count;
413 /***********************************************************************
414 * FONT_SelectObject
416 HFONT FONT_SelectObject( DC * dc, HFONT hfont, FONTOBJ * font )
418 static X_PHYSFONT stockFonts[LAST_STOCK_FONT-FIRST_STOCK_FONT+1];
420 static struct {
421 HFONT id;
422 LOGFONT16 logfont;
423 int access;
424 int used;
425 X_PHYSFONT cacheFont; } cacheFonts[FONTCACHE], *cacheFontsMin;
426 int i;
428 X_PHYSFONT * stockPtr;
429 HFONT prevHandle = dc->w.hFont;
430 XFontStruct * fontStruct;
431 dprintf_font(stddeb,"FONT_SelectObject(%p, %04x, %p)\n", dc, hfont, font);
433 #if 0 /* From the code in SelectObject, this can not happen */
434 /* Load font if necessary */
435 if (!font)
437 HFONT hnewfont;
439 hnewfont = CreateFont(10, 7, 0, 0, FW_DONTCARE,
440 FALSE, FALSE, FALSE, DEFAULT_CHARSET, 0, 0,
441 DEFAULT_QUALITY, FF_DONTCARE, "*" );
442 font = (FONTOBJ *) GDI_HEAP_LIN_ADDR( hnewfont );
444 #endif
446 if (dc->header.wMagic == METAFILE_DC_MAGIC)
447 if (MF_CreateFontIndirect(dc, hfont, &(font->logfont)))
448 return prevHandle;
449 else
450 return 0;
452 if ((hfont >= FIRST_STOCK_FONT) && (hfont <= LAST_STOCK_FONT))
453 stockPtr = &stockFonts[hfont - FIRST_STOCK_FONT];
454 else {
455 stockPtr = NULL;
457 * Ok, It's not a stock font but
458 * may be it's cached in dynamic cache
460 for(i=0; i<FONTCACHE; i++) /* search for same handle */
461 if (cacheFonts[i].id==hfont) { /* Got the handle */
463 * Check if Handle matches the font
465 if(memcmp(&cacheFonts[i].logfont,&(font->logfont), sizeof(LOGFONT16))) {
466 /* No: remove handle id from dynamic font cache */
467 cacheFonts[i].access=0;
468 cacheFonts[i].used=0;
469 cacheFonts[i].id=0;
470 /* may be there is an unused handle which contains the font */
471 for(i=0; i<FONTCACHE; i++) {
472 if((cacheFonts[i].used == 0) &&
473 (memcmp(&cacheFonts[i].logfont,&(font->logfont), sizeof(LOGFONT16)))== 0) {
474 /* got it load from cache and set new handle id */
475 stockPtr = &cacheFonts[i].cacheFont;
476 cacheFonts[i].access=1;
477 cacheFonts[i].used=1;
478 cacheFonts[i].id=hfont;
479 dprintf_font(stddeb,"FONT_SelectObject: got font from unused handle\n");
480 break;
485 else {
486 /* Yes: load from dynamic font cache */
487 stockPtr = &cacheFonts[i].cacheFont;
488 cacheFonts[i].access++;
489 cacheFonts[i].used++;
491 break;
494 if (!stockPtr || !stockPtr->fstruct)
496 if (!(fontStruct = FONT_MatchFont( &font->logfont, dc )))
498 /* If it is not a stock font, we can simply return 0 */
499 if (!stockPtr) return 0;
500 /* Otherwise we must try to find a substitute */
501 dprintf_font(stddeb,"Loading font 'fixed' for %04x\n", hfont );
502 font->logfont.lfPitchAndFamily &= ~VARIABLE_PITCH;
503 font->logfont.lfPitchAndFamily |= FIXED_PITCH;
504 fontStruct = XLoadQueryFont( display, "fixed" );
505 if (!fontStruct)
507 fprintf( stderr, "No system font could be found. Please check your font path.\n" );
508 exit( 1 );
512 else
514 fontStruct = stockPtr->fstruct;
515 dprintf_font(stddeb,
516 "FONT_SelectObject: Loaded font from cache %04x %p\n",
517 hfont, fontStruct );
520 /* Unuse previous font */
521 for (i=0; i < FONTCACHE; i++) {
522 if (cacheFonts[i].id == prevHandle) {
523 if(cacheFonts[i].used == 0)
524 fprintf(stderr, "Trying to decrement a use count of 0.\n");
525 else
526 cacheFonts[i].used--;
530 /* Store font */
531 dc->w.hFont = hfont;
532 if (stockPtr)
534 if (!stockPtr->fstruct)
536 stockPtr->fstruct = fontStruct;
537 FONT_GetMetrics( &font->logfont, fontStruct, &stockPtr->metrics );
539 memcpy( &dc->u.x.font, stockPtr, sizeof(*stockPtr) );
541 else
544 * Check in cacheFont
546 cacheFontsMin=NULL;
547 for (i=0; i < FONTCACHE; i++) {
548 if (cacheFonts[i].used==0)
549 if ((!cacheFontsMin) || ((cacheFontsMin) && (cacheFontsMin->access > cacheFonts[i].access)))
550 cacheFontsMin=&cacheFonts[i];
552 if (!cacheFontsMin) {
553 fprintf(stderr,"No unused font cache entry !!!!\n" );
554 return prevHandle;
556 if (cacheFontsMin->id!=0) {
557 dprintf_font(stddeb,
558 "FONT_SelectObject: Freeing %04x \n",cacheFontsMin->id );
559 XFreeFont( display, cacheFontsMin->cacheFont.fstruct );
561 cacheFontsMin->cacheFont.fstruct = fontStruct;
562 FONT_GetMetrics( &font->logfont, fontStruct, &cacheFontsMin->cacheFont.metrics );
563 cacheFontsMin->access=1;
564 cacheFontsMin->used=1;
565 cacheFontsMin->id=hfont;
566 memcpy( &dc->u.x.font, &(cacheFontsMin->cacheFont), sizeof(cacheFontsMin->cacheFont) );
567 memcpy(&cacheFontsMin->logfont,&(font->logfont), sizeof(LOGFONT16));
570 return prevHandle;
574 /***********************************************************************
575 * GetTextCharacterExtra (GDI.89)
577 short GetTextCharacterExtra( HDC hdc )
579 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
580 if (!dc) return 0;
581 return abs( (dc->w.charExtra * dc->w.WndExtX + dc->w.VportExtX / 2)
582 / dc->w.VportExtX );
586 /***********************************************************************
587 * SetTextCharacterExtra (GDI.8)
589 short SetTextCharacterExtra( HDC hdc, short extra )
591 short prev;
592 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
593 if (!dc) return 0;
594 extra = (extra * dc->w.VportExtX + dc->w.WndExtX / 2) / dc->w.WndExtX;
595 prev = dc->w.charExtra;
596 dc->w.charExtra = abs(extra);
597 return (prev * dc->w.WndExtX + dc->w.VportExtX / 2) / dc->w.VportExtX;
601 /***********************************************************************
602 * SetTextJustification (GDI.10)
604 short SetTextJustification( HDC hdc, short extra, short breaks )
606 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
607 if (!dc) return 0;
609 extra = abs((extra * dc->w.VportExtX + dc->w.WndExtX / 2) / dc->w.WndExtX);
610 if (!extra) breaks = 0;
611 dc->w.breakTotalExtra = extra;
612 dc->w.breakCount = breaks;
613 if (breaks)
615 dc->w.breakExtra = extra / breaks;
616 dc->w.breakRem = extra - (dc->w.breakCount * dc->w.breakExtra);
618 else
620 dc->w.breakExtra = 0;
621 dc->w.breakRem = 0;
623 return 1;
627 /***********************************************************************
628 * GetTextFace (GDI.92)
630 INT GetTextFace( HDC hdc, INT count, LPSTR name )
632 FONTOBJ *font;
634 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
635 if (!dc) return 0;
636 if (!(font = (FONTOBJ *) GDI_GetObjPtr( dc->w.hFont, FONT_MAGIC )))
637 return 0;
638 lstrcpyn32A( name, font->logfont.lfFaceName, count );
639 return strlen(name);
643 /***********************************************************************
644 * GetTextExtent (GDI.91)
646 DWORD GetTextExtent( HDC hdc, LPCSTR str, short count )
648 SIZE16 size;
649 if (!GetTextExtentPoint16( hdc, str, count, &size )) return 0;
650 return MAKELONG( size.cx, size.cy );
654 /***********************************************************************
655 * GetTextExtentPoint16 (GDI.471)
657 BOOL16 GetTextExtentPoint16( HDC16 hdc, LPCSTR str, INT16 count, LPSIZE16 size)
659 SIZE32 size32;
660 BOOL32 ret = GetTextExtentPoint32A( hdc, str, count, &size32 );
661 CONV_SIZE32TO16( &size32, size );
662 return (BOOL16)ret;
666 /***********************************************************************
667 * GetTextExtentPoint32A (GDI32.232)
669 BOOL32 GetTextExtentPoint32A( HDC32 hdc, LPCSTR str, INT32 count,
670 LPSIZE32 size )
672 int dir, ascent, descent;
673 XCharStruct info;
675 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
676 if (!dc) return FALSE;
677 XTextExtents( dc->u.x.font.fstruct, str, count, &dir,
678 &ascent, &descent, &info );
679 size->cx = abs((info.width + dc->w.breakRem + count * dc->w.charExtra)
680 * dc->w.WndExtX / dc->w.VportExtX);
681 size->cy = abs((dc->u.x.font.fstruct->ascent+dc->u.x.font.fstruct->descent)
682 * dc->w.WndExtY / dc->w.VportExtY);
684 dprintf_font(stddeb,"GetTextExtentPoint(%08x '%*.*s' %d %p): returning %d,%d\n",
685 hdc, count, count, str, count, size, size->cx, size->cy );
686 return TRUE;
690 /***********************************************************************
691 * GetTextExtentPoint32W (GDI32.233)
693 BOOL32 GetTextExtentPoint32W( HDC32 hdc, LPCWSTR str, INT32 count,
694 LPSIZE32 size )
696 char *p = STRING32_DupUniToAnsi( str );
697 BOOL32 ret = GetTextExtentPoint32A( hdc, p, count, size );
698 free( p );
699 return ret;
703 /***********************************************************************
704 * GetTextMetrics (GDI.93)
706 BOOL GetTextMetrics( HDC hdc, LPTEXTMETRIC16 metrics )
708 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
709 if (!dc) return FALSE;
710 memcpy( metrics, &dc->u.x.font.metrics, sizeof(*metrics) );
712 metrics->tmAscent = abs( metrics->tmAscent
713 * dc->w.WndExtY / dc->w.VportExtY );
714 metrics->tmDescent = abs( metrics->tmDescent
715 * dc->w.WndExtY / dc->w.VportExtY );
716 metrics->tmHeight = metrics->tmAscent + metrics->tmDescent;
717 metrics->tmInternalLeading = abs( metrics->tmInternalLeading
718 * dc->w.WndExtY / dc->w.VportExtY );
719 metrics->tmExternalLeading = abs( metrics->tmExternalLeading
720 * dc->w.WndExtY / dc->w.VportExtY );
721 metrics->tmMaxCharWidth = abs( metrics->tmMaxCharWidth
722 * dc->w.WndExtX / dc->w.VportExtX );
723 metrics->tmAveCharWidth = abs( metrics->tmAveCharWidth
724 * dc->w.WndExtX / dc->w.VportExtX );
726 dprintf_font(stdnimp,"text metrics:\n
727 InternalLeading = %i
728 ExternalLeading = %i
729 MaxCharWidth = %i
730 Weight = %i
731 Italic = %i
732 Underlined = %i
733 StruckOut = %i
734 FirstChar = %i
735 LastChar = %i
736 DefaultChar = %i
737 BreakChar = %i
738 CharSet = %i
739 Overhang = %i
740 DigitizedAspectX = %i
741 DigitizedAspectY = %i
742 AveCharWidth = %i
743 MaxCharWidth = %i
744 Ascent = %i
745 Descent = %i
746 Height = %i\n",
747 metrics->tmInternalLeading,
748 metrics->tmExternalLeading,
749 metrics->tmMaxCharWidth,
750 metrics->tmWeight,
751 metrics->tmItalic,
752 metrics->tmUnderlined,
753 metrics->tmStruckOut,
754 metrics->tmFirstChar,
755 metrics->tmLastChar,
756 metrics->tmDefaultChar,
757 metrics->tmBreakChar,
758 metrics->tmCharSet,
759 metrics->tmOverhang,
760 metrics->tmDigitizedAspectX,
761 metrics->tmDigitizedAspectY,
762 metrics->tmAveCharWidth,
763 metrics->tmMaxCharWidth,
764 metrics->tmAscent,
765 metrics->tmDescent,
766 metrics->tmHeight);
768 return TRUE;
772 /***********************************************************************
773 * SetMapperFlags (GDI.349)
775 DWORD SetMapperFlags(HDC hDC, DWORD dwFlag)
777 dprintf_font(stdnimp,"SetmapperFlags(%04x, %08lX) // Empty Stub !\n",
778 hDC, dwFlag);
779 return 0L;
783 /***********************************************************************
784 * GetCharABCWidths (GDI.307)
786 BOOL GetCharABCWidths(HDC hdc, UINT wFirstChar, UINT wLastChar, LPABC16 lpABC)
789 /* No TrueType fonts in Wine so far */
791 fprintf(stdnimp,"STUB: GetCharABCWidths(%04x,%04x,%04x,%08x)\n",
792 hdc,wFirstChar,wLastChar,(unsigned)lpABC);
794 return FALSE;
798 /***********************************************************************
799 * GetCharWidth (GDI.350)
801 BOOL GetCharWidth(HDC hdc, WORD wFirstChar, WORD wLastChar, LPINT16 lpBuffer)
803 int i, j;
804 XFontStruct *xfont;
805 XCharStruct *cs, *def;
807 DC *dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC);
808 if (!dc) return FALSE;
809 xfont = dc->u.x.font.fstruct;
811 /* fixed font? */
812 if (xfont->per_char == NULL)
814 for (i = wFirstChar, j = 0; i <= wLastChar; i++, j++)
815 *(lpBuffer + j) = xfont->max_bounds.width;
816 return TRUE;
819 CI_GET_DEFAULT_INFO(xfont, def);
821 for (i = wFirstChar, j = 0; i <= wLastChar; i++, j++)
823 CI_GET_CHAR_INFO(xfont, i, def, cs);
824 *(lpBuffer + j) = cs ? cs->width : xfont->max_bounds.width;
825 if (*(lpBuffer + j) < 0)
826 *(lpBuffer + j) = 0;
828 return TRUE;
832 /***********************************************************************
833 * AddFontResource (GDI.119)
835 INT AddFontResource( LPCSTR str )
837 fprintf( stdnimp, "STUB: AddFontResource('%s')\n", str );
838 return 1;
842 /***********************************************************************
843 * RemoveFontResource (GDI.136)
845 BOOL RemoveFontResource( LPSTR str )
847 fprintf( stdnimp, "STUB: RemoveFontResource('%s')\n", str );
848 return TRUE;
852 /*************************************************************************
853 * ParseFontParms [internal]
855 int ParseFontParms(LPSTR lpFont, WORD wParmsNo, LPSTR lpRetStr, WORD wMaxSiz)
857 int i;
858 if (lpFont == NULL) return 0;
859 if (lpRetStr == NULL) return 0;
860 for (i = 0; (*lpFont != '\0' && i != wParmsNo); ) {
861 if (*lpFont == '-') i++;
862 lpFont++;
864 if (i == wParmsNo) {
865 if (*lpFont == '-') lpFont++;
866 wMaxSiz--;
867 for (i = 0; (*lpFont != '\0' && *lpFont != '-' && i < wMaxSiz); i++)
868 *(lpRetStr + i) = *lpFont++;
869 *(lpRetStr + i) = '\0';
870 return i;
872 else
873 lpRetStr[0] = '\0';
874 return 0;
878 /*************************************************************************
879 * InitFontsList [internal]
882 static int logfcmp(const void *a,const void *b)
884 return strcmp( (*(LPLOGFONT16 *)a)->lfFaceName,
885 (*(LPLOGFONT16 *)b)->lfFaceName );
888 void InitFontsList(void)
890 char str[32];
891 char pattern[100];
892 char *family, *weight, *charset;
893 char **names;
894 char slant, spacing;
895 int i, count;
896 LPLOGFONT16 lpNewFont;
897 weight = "medium";
898 slant = 'r';
899 spacing = '*';
900 charset = "*";
901 family = "*-*";
902 dprintf_font(stddeb,"InitFontsList !\n");
903 sprintf( pattern, "-%s-%s-%c-normal-*-*-*-*-*-%c-*-%s",
904 family, weight, slant, spacing, charset);
905 names = XListFonts( display, pattern, MAX_FONTS, &count );
906 dprintf_font(stddeb,"InitFontsList // count=%d \n", count);
907 for (i = 0; i < count; i++) {
908 lpNewFont = malloc(sizeof(LOGFONT16) + LF_FACESIZE);
909 if (lpNewFont == NULL) {
910 dprintf_font(stddeb, "InitFontsList // Error alloc new font structure !\n");
911 break;
913 dprintf_font(stddeb,"InitFontsList // names[%d]='%s' \n", i, names[i]);
914 ParseFontParms(names[i], 2, str, sizeof(str));
915 #if 0
916 /* not necessary because new function FONT_ChkX11Family() */
917 if (strcmp(str, "fixed") == 0) strcat(str, "sys");
918 #endif
919 AnsiUpper(str);
920 strcpy(lpNewFont->lfFaceName, str);
921 ParseFontParms(names[i], 8, str, sizeof(str));
922 lpNewFont->lfHeight = atoi(str) / 10;
923 ParseFontParms(names[i], 12, str, sizeof(str));
924 lpNewFont->lfWidth = atoi(str) / 10;
925 lpNewFont->lfEscapement = 0;
926 lpNewFont->lfOrientation = 0;
927 lpNewFont->lfWeight = FW_REGULAR;
928 lpNewFont->lfItalic = 0;
929 lpNewFont->lfUnderline = 0;
930 lpNewFont->lfStrikeOut = 0;
931 ParseFontParms(names[i], 13, str, sizeof(str));
932 if (strcmp(str, "iso8859") == 0) {
933 lpNewFont->lfCharSet = ANSI_CHARSET;
934 } else {
935 lpNewFont->lfCharSet = OEM_CHARSET;
937 lpNewFont->lfOutPrecision = OUT_DEFAULT_PRECIS;
938 lpNewFont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
939 lpNewFont->lfQuality = DEFAULT_QUALITY;
940 ParseFontParms(names[i], 11, str, sizeof(str));
941 switch(str[0]) {
942 case 'p':
943 lpNewFont->lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
944 break;
945 case 'm':
946 case 'c':
947 lpNewFont->lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
948 break;
949 default:
950 lpNewFont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
951 break;
953 dprintf_font(stddeb,"InitFontsList // lpNewFont->lfHeight=%d \n", lpNewFont->lfHeight);
954 dprintf_font(stddeb,"InitFontsList // lpNewFont->lfWidth=%d \n", lpNewFont->lfWidth);
955 dprintf_font(stddeb,"InitFontsList // lfFaceName='%s' \n", lpNewFont->lfFaceName);
956 lpLogFontList[i] = lpNewFont;
957 lpLogFontList[i+1] = NULL;
959 qsort(lpLogFontList,count,sizeof(*lpLogFontList),logfcmp);
960 XFreeFontNames(names);
964 /*************************************************************************
965 * EnumFonts [GDI.70]
967 INT EnumFonts(HDC hDC, LPCSTR lpFaceName, FONTENUMPROC lpEnumFunc, LPARAM lpData)
969 HANDLE hLog;
970 HANDLE hMet;
971 HFONT hFont;
972 HFONT hOldFont;
973 LPLOGFONT16 lpLogFont;
974 LPTEXTMETRIC16 lptm;
975 LPSTR lpOldName;
976 char FaceName[LF_FACESIZE];
977 int nRet = 0;
978 int i;
980 dprintf_font(stddeb,"EnumFonts(%04x, %p='%s', %08lx, %08lx)\n",
981 hDC, lpFaceName, lpFaceName, (LONG)lpEnumFunc, lpData);
982 if (lpEnumFunc == 0) return 0;
983 hLog = GDI_HEAP_ALLOC( sizeof(LOGFONT16) + LF_FACESIZE );
984 lpLogFont = (LPLOGFONT16) GDI_HEAP_LIN_ADDR(hLog);
985 if (lpLogFont == NULL) {
986 fprintf(stderr,"EnumFonts // can't alloc LOGFONT struct !\n");
987 return 0;
989 hMet = GDI_HEAP_ALLOC( sizeof(TEXTMETRIC16) );
990 lptm = (LPTEXTMETRIC16) GDI_HEAP_LIN_ADDR(hMet);
991 if (lptm == NULL) {
992 GDI_HEAP_FREE(hLog);
993 fprintf(stderr, "EnumFonts // can't alloc TEXTMETRIC struct !\n");
994 return 0;
996 if (lpFaceName != NULL) {
997 strcpy(FaceName, lpFaceName);
998 AnsiUpper(FaceName);
1000 lpOldName = NULL;
1002 if (lpLogFontList[0] == NULL) InitFontsList();
1003 for(i = 0; lpLogFontList[i] != NULL; i++) {
1004 if (lpFaceName == NULL) {
1005 if (lpOldName != NULL) {
1006 if (strcmp(lpOldName,lpLogFontList[i]->lfFaceName) == 0) continue;
1008 lpOldName = lpLogFontList[i]->lfFaceName;
1009 } else {
1010 if (strcmp(FaceName, lpLogFontList[i]->lfFaceName) != 0) continue;
1012 dprintf_font(stddeb,"EnumFonts // enum '%s' !\n", lpLogFontList[i]->lfFaceName);
1013 dprintf_font(stddeb,"EnumFonts // %p !\n", lpLogFontList[i]);
1014 memcpy(lpLogFont, lpLogFontList[i], sizeof(LOGFONT16) + LF_FACESIZE);
1015 hFont = CreateFontIndirect(lpLogFont);
1016 hOldFont = SelectObject(hDC, hFont);
1017 GetTextMetrics(hDC, lptm);
1018 SelectObject(hDC, hOldFont);
1019 DeleteObject(hFont);
1020 dprintf_font(stddeb,"EnumFonts // i=%d lpLogFont=%p lptm=%p\n", i, lpLogFont, lptm);
1021 nRet = CallEnumFontsProc(lpEnumFunc, GDI_HEAP_SEG_ADDR(hLog),
1022 GDI_HEAP_SEG_ADDR(hMet), 0, (LONG)lpData );
1023 if (nRet == 0) {
1024 dprintf_font(stddeb,"EnumFonts // EnumEnd requested by application !\n");
1025 break;
1028 GDI_HEAP_FREE(hMet);
1029 GDI_HEAP_FREE(hLog);
1030 return nRet;
1034 /*************************************************************************
1035 * EnumFontFamilies [GDI.330]
1037 INT EnumFontFamilies(HDC hDC, LPCSTR lpszFamily, FONTENUMPROC lpEnumFunc, LPARAM lpData)
1039 HANDLE hLog;
1040 HANDLE hMet;
1041 HFONT hFont;
1042 HFONT hOldFont;
1043 LPENUMLOGFONT16 lpEnumLogFont;
1044 LPTEXTMETRIC16 lptm;
1045 LPSTR lpOldName;
1046 char FaceName[LF_FACESIZE];
1047 int nRet = 0;
1048 int i;
1050 dprintf_font(stddeb,"EnumFontFamilies(%04x, %p, %08lx, %08lx)\n",
1051 hDC, lpszFamily, (DWORD)lpEnumFunc, lpData);
1052 if (lpEnumFunc == 0) return 0;
1053 hLog = GDI_HEAP_ALLOC( sizeof(ENUMLOGFONT16) );
1054 lpEnumLogFont = (LPENUMLOGFONT16) GDI_HEAP_LIN_ADDR(hLog);
1055 if (lpEnumLogFont == NULL) {
1056 fprintf(stderr,"EnumFontFamilies // can't alloc LOGFONT struct !\n");
1057 return 0;
1059 hMet = GDI_HEAP_ALLOC( sizeof(TEXTMETRIC16) );
1060 lptm = (LPTEXTMETRIC16) GDI_HEAP_LIN_ADDR(hMet);
1061 if (lptm == NULL) {
1062 GDI_HEAP_FREE(hLog);
1063 fprintf(stderr,"EnumFontFamilies // can't alloc TEXTMETRIC struct !\n");
1064 return 0;
1066 lpOldName = NULL;
1067 if (lpszFamily != NULL) {
1068 strcpy(FaceName, lpszFamily);
1069 AnsiUpper(FaceName);
1071 if (lpLogFontList[0] == NULL) InitFontsList();
1072 for(i = 0; lpLogFontList[i] != NULL; i++) {
1073 if (lpszFamily == NULL) {
1074 if (lpOldName != NULL) {
1075 if (strcmp(lpOldName,lpLogFontList[i]->lfFaceName) == 0) continue;
1077 lpOldName = lpLogFontList[i]->lfFaceName;
1078 } else {
1079 if (strcmp(FaceName, lpLogFontList[i]->lfFaceName) != 0) continue;
1081 memcpy(lpEnumLogFont, lpLogFontList[i], sizeof(LOGFONT16));
1082 strcpy(lpEnumLogFont->elfFullName,"");
1083 strcpy(lpEnumLogFont->elfStyle,"");
1084 hFont = CreateFontIndirect((LPLOGFONT16)lpEnumLogFont);
1085 hOldFont = SelectObject(hDC, hFont);
1086 GetTextMetrics(hDC, lptm);
1087 SelectObject(hDC, hOldFont);
1088 DeleteObject(hFont);
1089 dprintf_font(stddeb, "EnumFontFamilies // i=%d lpLogFont=%p lptm=%p\n", i, lpEnumLogFont, lptm);
1091 nRet = CallEnumFontFamProc( lpEnumFunc,
1092 GDI_HEAP_SEG_ADDR(hLog),
1093 GDI_HEAP_SEG_ADDR(hMet),
1094 0, lpData );
1095 if (nRet == 0) {
1096 dprintf_font(stddeb,"EnumFontFamilies // EnumEnd requested by application !\n");
1097 break;
1100 GDI_HEAP_FREE(hMet);
1101 GDI_HEAP_FREE(hLog);
1102 return nRet;
1105 /*************************************************************************
1106 * GetRasterizerCaps [GDI.313]
1109 BOOL GetRasterizerCaps(LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
1111 /* This is not much more than a dummy */
1112 RASTERIZER_STATUS rs;
1114 rs.nSize = sizeof(rs);
1115 rs.wFlags = 0;
1116 rs.nLanguageID = 0;
1117 return True;
1120 /*************************************************************************
1121 * GetKerningPairs [GDI.332]
1123 int GetKerningPairs(HDC hDC,int cBufLen,LPKERNINGPAIR16 lpKerningPairs)
1125 /* Wine fonts are ugly and don't support kerning :) */
1126 return 0;