Release 960712
[wine/multimedia.git] / objects / font.c
blob29a76026fbada32e37a4a26704c2df758d7cbc38
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+1];
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( !lstrcmpi32A(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 ;-) */
269 AnsiUpper(font->lfFaceName);
271 fontStruct = XLoadQueryFont( display, *names );
272 XFreeFontNames( names );
273 return fontStruct;
277 /***********************************************************************
278 * FONT_GetMetrics
280 void FONT_GetMetrics( LOGFONT16 * logfont, XFontStruct * xfont,
281 TEXTMETRIC16 * metrics )
283 int average, i, count;
284 unsigned long prop;
286 metrics->tmAscent = xfont->ascent;
287 metrics->tmDescent = xfont->descent;
288 metrics->tmHeight = xfont->ascent + xfont->descent;
290 metrics->tmInternalLeading = 0;
291 if (XGetFontProperty( xfont, XA_X_HEIGHT, &prop ))
292 metrics->tmInternalLeading = xfont->ascent - (short)prop;
293 metrics->tmExternalLeading = 0;
294 metrics->tmMaxCharWidth = xfont->max_bounds.width;
295 metrics->tmWeight = logfont->lfWeight;
296 metrics->tmItalic = logfont->lfItalic;
297 metrics->tmUnderlined = logfont->lfUnderline;
298 metrics->tmStruckOut = logfont->lfStrikeOut;
299 metrics->tmFirstChar = xfont->min_char_or_byte2;
300 metrics->tmLastChar = xfont->max_char_or_byte2;
301 metrics->tmDefaultChar = xfont->default_char;
302 metrics->tmBreakChar = ' ';
303 metrics->tmCharSet = logfont->lfCharSet;
304 metrics->tmOverhang = 0;
305 metrics->tmDigitizedAspectX = 1;
306 metrics->tmDigitizedAspectY = 1;
307 metrics->tmPitchAndFamily = (logfont->lfPitchAndFamily&0xf0)|TMPF_DEVICE;
308 if (logfont->lfPitchAndFamily & FIXED_PITCH)
309 metrics->tmPitchAndFamily |= TMPF_FIXED_PITCH;
311 if (!xfont->per_char) average = metrics->tmMaxCharWidth;
312 else
314 XCharStruct * charPtr = xfont->per_char;
315 average = count = 0;
316 for (i = metrics->tmFirstChar; i <= metrics->tmLastChar; i++)
318 if (!CI_NONEXISTCHAR( charPtr ))
320 average += charPtr->width;
321 count++;
323 charPtr++;
325 if (count) average = (average + count/2) / count;
327 metrics->tmAveCharWidth = average;
330 /***********************************************************************
331 * GetGlyphOutLine (GDI.309)
333 DWORD GetGlyphOutLine(HDC hdc, UINT uChar, UINT fuFormat, LPGLYPHMETRICS lpgm,
334 DWORD cbBuffer, LPSTR lpBuffer, LPMAT2 lpmat2)
336 fprintf( stdnimp,"GetGlyphOutLine(%04x, '%c', %04x, %p, %ld, %p, %p) // - empty stub!\n",
337 hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
338 return (DWORD)-1; /* failure */
342 /***********************************************************************
343 * CreateScalableFontResource (GDI.310)
345 BOOL CreateScalableFontResource( UINT fHidden,LPSTR lpszResourceFile,
346 LPSTR lpszFontFile, LPSTR lpszCurrentPath )
348 /* fHidden=1 - only visible for the calling app, read-only, not
349 * enumbered with EnumFonts/EnumFontFamilies
350 * lpszCurrentPath can be NULL
352 fprintf(stdnimp,"CreateScalableFontResource(%d,%s,%s,%s) // empty stub!\n",
353 fHidden, lpszResourceFile, lpszFontFile, lpszCurrentPath );
354 return FALSE; /* create failed */
358 /***********************************************************************
359 * CreateFontIndirect16 (GDI.57)
361 HFONT16 CreateFontIndirect16( const LOGFONT16 *font )
363 FONTOBJ * fontPtr;
364 HFONT16 hfont;
366 if (!font)
368 fprintf(stderr,"CreateFontIndirect: font is NULL : returning NULL\n");
369 return 0;
371 hfont = GDI_AllocObject( sizeof(FONTOBJ), FONT_MAGIC );
372 if (!hfont) return 0;
373 fontPtr = (FONTOBJ *) GDI_HEAP_LIN_ADDR( hfont );
374 memcpy( &fontPtr->logfont, font, sizeof(LOGFONT16) );
375 AnsiLower( fontPtr->logfont.lfFaceName );
376 dprintf_font(stddeb,"CreateFontIndirect(%p (%d,%d)); return %04x\n",
377 font, font->lfHeight, font->lfWidth, hfont);
378 return hfont;
382 /***********************************************************************
383 * CreateFontIndirect32A (GDI32.44)
385 HFONT32 CreateFontIndirect32A( const LOGFONT32A *font )
387 LOGFONT16 font16;
389 font16.lfHeight = (INT16)font->lfHeight;
390 font16.lfWidth = (INT16)font->lfWidth;
391 font16.lfEscapement = (INT16)font->lfEscapement;
392 font16.lfOrientation = (INT16)font->lfOrientation;
393 font16.lfWeight = (INT16)font->lfWeight;
394 font16.lfItalic = font->lfItalic;
395 font16.lfUnderline = font->lfUnderline;
396 font16.lfStrikeOut = font->lfStrikeOut;
397 font16.lfCharSet = font->lfCharSet;
398 font16.lfOutPrecision = font->lfOutPrecision;
399 font16.lfClipPrecision = font->lfClipPrecision;
400 font16.lfQuality = font->lfQuality;
401 font16.lfPitchAndFamily = font->lfPitchAndFamily;
402 lstrcpyn32A( font16.lfFaceName, font->lfFaceName, LF_FACESIZE );
403 return CreateFontIndirect16( &font16 );
407 /***********************************************************************
408 * CreateFontIndirect32W (GDI32.45)
410 HFONT32 CreateFontIndirect32W( const LOGFONT32W *font )
412 LOGFONT16 font16;
414 font16.lfHeight = (INT16)font->lfHeight;
415 font16.lfWidth = (INT16)font->lfWidth;
416 font16.lfEscapement = (INT16)font->lfEscapement;
417 font16.lfOrientation = (INT16)font->lfOrientation;
418 font16.lfWeight = (INT16)font->lfWeight;
419 font16.lfItalic = font->lfItalic;
420 font16.lfUnderline = font->lfUnderline;
421 font16.lfStrikeOut = font->lfStrikeOut;
422 font16.lfCharSet = font->lfCharSet;
423 font16.lfOutPrecision = font->lfOutPrecision;
424 font16.lfClipPrecision = font->lfClipPrecision;
425 font16.lfQuality = font->lfQuality;
426 font16.lfPitchAndFamily = font->lfPitchAndFamily;
427 lstrcpynWtoA( font16.lfFaceName, font->lfFaceName, LF_FACESIZE );
428 return CreateFontIndirect16( &font16 );
432 /***********************************************************************
433 * CreateFont (GDI.56)
435 HFONT CreateFont( INT height, INT width, INT esc, INT orient, INT weight,
436 BYTE italic, BYTE underline, BYTE strikeout, BYTE charset,
437 BYTE outpres, BYTE clippres, BYTE quality, BYTE pitch,
438 LPCSTR name )
440 LOGFONT16 logfont = {height, width, esc, orient, weight, italic, underline,
441 strikeout, charset, outpres, clippres, quality, pitch, };
442 dprintf_font(stddeb,"CreateFont(%d,%d)\n", height, width);
443 if (name) lstrcpyn32A(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
444 else logfont.lfFaceName[0] = '\0';
445 return CreateFontIndirect16( &logfont );
449 /***********************************************************************
450 * FONT_GetObject
452 int FONT_GetObject( FONTOBJ * font, int count, LPSTR buffer )
454 if (count > sizeof(LOGFONT16)) count = sizeof(LOGFONT16);
455 memcpy( buffer, &font->logfont, count );
456 return count;
460 /***********************************************************************
461 * FONT_SelectObject
463 HFONT FONT_SelectObject( DC * dc, HFONT hfont, FONTOBJ * font )
465 static X_PHYSFONT stockFonts[LAST_STOCK_FONT-FIRST_STOCK_FONT+1];
467 static struct {
468 HFONT id;
469 LOGFONT16 logfont;
470 int access;
471 int used;
472 X_PHYSFONT cacheFont; } cacheFonts[FONTCACHE], *cacheFontsMin;
473 int i;
475 X_PHYSFONT * stockPtr;
476 HFONT prevHandle = dc->w.hFont;
477 XFontStruct * fontStruct;
478 dprintf_font(stddeb,"FONT_SelectObject(%p, %04x, %p)\n", dc, hfont, font);
480 #if 0 /* From the code in SelectObject, this can not happen */
481 /* Load font if necessary */
482 if (!font)
484 HFONT hnewfont;
486 hnewfont = CreateFont(10, 7, 0, 0, FW_DONTCARE,
487 FALSE, FALSE, FALSE, DEFAULT_CHARSET, 0, 0,
488 DEFAULT_QUALITY, FF_DONTCARE, "*" );
489 font = (FONTOBJ *) GDI_HEAP_LIN_ADDR( hnewfont );
491 #endif
493 if (dc->header.wMagic == METAFILE_DC_MAGIC)
494 if (MF_CreateFontIndirect(dc, hfont, &(font->logfont)))
495 return prevHandle;
496 else
497 return 0;
499 if ((hfont >= FIRST_STOCK_FONT) && (hfont <= LAST_STOCK_FONT))
500 stockPtr = &stockFonts[hfont - FIRST_STOCK_FONT];
501 else {
502 stockPtr = NULL;
504 * Ok, It's not a stock font but
505 * may be it's cached in dynamic cache
507 for(i=0; i<FONTCACHE; i++) /* search for same handle */
508 if (cacheFonts[i].id==hfont) { /* Got the handle */
510 * Check if Handle matches the font
512 if(memcmp(&cacheFonts[i].logfont,&(font->logfont), sizeof(LOGFONT16))) {
513 /* No: remove handle id from dynamic font cache */
514 cacheFonts[i].access=0;
515 cacheFonts[i].used=0;
516 cacheFonts[i].id=0;
517 /* may be there is an unused handle which contains the font */
518 for(i=0; i<FONTCACHE; i++) {
519 if((cacheFonts[i].used == 0) &&
520 (memcmp(&cacheFonts[i].logfont,&(font->logfont), sizeof(LOGFONT16)))== 0) {
521 /* got it load from cache and set new handle id */
522 stockPtr = &cacheFonts[i].cacheFont;
523 cacheFonts[i].access=1;
524 cacheFonts[i].used=1;
525 cacheFonts[i].id=hfont;
526 dprintf_font(stddeb,"FONT_SelectObject: got font from unused handle\n");
527 break;
532 else {
533 /* Yes: load from dynamic font cache */
534 stockPtr = &cacheFonts[i].cacheFont;
535 cacheFonts[i].access++;
536 cacheFonts[i].used++;
538 break;
541 if (!stockPtr || !stockPtr->fstruct)
543 if (!(fontStruct = FONT_MatchFont( &font->logfont, dc )))
545 /* If it is not a stock font, we can simply return 0 */
546 if (!stockPtr) return 0;
547 /* Otherwise we must try to find a substitute */
548 dprintf_font(stddeb,"Loading font 'fixed' for %04x\n", hfont );
549 font->logfont.lfPitchAndFamily &= ~VARIABLE_PITCH;
550 font->logfont.lfPitchAndFamily |= FIXED_PITCH;
551 fontStruct = XLoadQueryFont( display, "fixed" );
552 if (!fontStruct)
554 fprintf( stderr, "No system font could be found. Please check your font path.\n" );
555 exit( 1 );
559 else
561 fontStruct = stockPtr->fstruct;
562 dprintf_font(stddeb,
563 "FONT_SelectObject: Loaded font from cache %04x %p\n",
564 hfont, fontStruct );
567 /* Unuse previous font */
568 for (i=0; i < FONTCACHE; i++) {
569 if (cacheFonts[i].id == prevHandle) {
570 if(cacheFonts[i].used == 0)
571 fprintf(stderr, "Trying to decrement a use count of 0.\n");
572 else
573 cacheFonts[i].used--;
577 /* Store font */
578 dc->w.hFont = hfont;
579 if (stockPtr)
581 if (!stockPtr->fstruct)
583 stockPtr->fstruct = fontStruct;
584 FONT_GetMetrics( &font->logfont, fontStruct, &stockPtr->metrics );
586 memcpy( &dc->u.x.font, stockPtr, sizeof(*stockPtr) );
588 else
591 * Check in cacheFont
593 cacheFontsMin=NULL;
594 for (i=0; i < FONTCACHE; i++) {
595 if (cacheFonts[i].used==0)
596 if ((!cacheFontsMin) || ((cacheFontsMin) && (cacheFontsMin->access > cacheFonts[i].access)))
597 cacheFontsMin=&cacheFonts[i];
599 if (!cacheFontsMin) {
600 fprintf(stderr,"No unused font cache entry !!!!\n" );
601 return prevHandle;
603 if (cacheFontsMin->id!=0) {
604 dprintf_font(stddeb,
605 "FONT_SelectObject: Freeing %04x \n",cacheFontsMin->id );
606 XFreeFont( display, cacheFontsMin->cacheFont.fstruct );
608 cacheFontsMin->cacheFont.fstruct = fontStruct;
609 FONT_GetMetrics( &font->logfont, fontStruct, &cacheFontsMin->cacheFont.metrics );
610 cacheFontsMin->access=1;
611 cacheFontsMin->used=1;
612 cacheFontsMin->id=hfont;
613 memcpy( &dc->u.x.font, &(cacheFontsMin->cacheFont), sizeof(cacheFontsMin->cacheFont) );
614 memcpy(&cacheFontsMin->logfont,&(font->logfont), sizeof(LOGFONT16));
617 return prevHandle;
621 /***********************************************************************
622 * GetTextCharacterExtra (GDI.89)
624 short GetTextCharacterExtra( HDC hdc )
626 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
627 if (!dc) return 0;
628 return abs( (dc->w.charExtra * dc->w.WndExtX + dc->w.VportExtX / 2)
629 / dc->w.VportExtX );
633 /***********************************************************************
634 * SetTextCharacterExtra (GDI.8)
636 short SetTextCharacterExtra( HDC hdc, short extra )
638 short prev;
639 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
640 if (!dc) return 0;
641 extra = (extra * dc->w.VportExtX + dc->w.WndExtX / 2) / dc->w.WndExtX;
642 prev = dc->w.charExtra;
643 dc->w.charExtra = abs(extra);
644 return (prev * dc->w.WndExtX + dc->w.VportExtX / 2) / dc->w.VportExtX;
648 /***********************************************************************
649 * SetTextJustification (GDI.10)
651 short SetTextJustification( HDC hdc, short extra, short breaks )
653 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
654 if (!dc) return 0;
656 extra = abs((extra * dc->w.VportExtX + dc->w.WndExtX / 2) / dc->w.WndExtX);
657 if (!extra) breaks = 0;
658 dc->w.breakTotalExtra = extra;
659 dc->w.breakCount = breaks;
660 if (breaks)
662 dc->w.breakExtra = extra / breaks;
663 dc->w.breakRem = extra - (dc->w.breakCount * dc->w.breakExtra);
665 else
667 dc->w.breakExtra = 0;
668 dc->w.breakRem = 0;
670 return 1;
674 /***********************************************************************
675 * GetTextFace (GDI.92)
677 INT GetTextFace( HDC hdc, INT count, LPSTR name )
679 FONTOBJ *font;
681 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
682 if (!dc) return 0;
683 if (!(font = (FONTOBJ *) GDI_GetObjPtr( dc->w.hFont, FONT_MAGIC )))
684 return 0;
685 lstrcpyn32A( name, font->logfont.lfFaceName, count );
686 return strlen(name);
690 /***********************************************************************
691 * GetTextExtent (GDI.91)
693 DWORD GetTextExtent( HDC hdc, LPCSTR str, short count )
695 SIZE16 size;
696 if (!GetTextExtentPoint16( hdc, str, count, &size )) return 0;
697 return MAKELONG( size.cx, size.cy );
701 /***********************************************************************
702 * GetTextExtentPoint16 (GDI.471)
704 BOOL16 GetTextExtentPoint16( HDC16 hdc, LPCSTR str, INT16 count, LPSIZE16 size)
706 SIZE32 size32;
707 BOOL32 ret = GetTextExtentPoint32A( hdc, str, count, &size32 );
708 CONV_SIZE32TO16( &size32, size );
709 return (BOOL16)ret;
713 /***********************************************************************
714 * GetTextExtentPoint32A (GDI32.232)
716 BOOL32 GetTextExtentPoint32A( HDC32 hdc, LPCSTR str, INT32 count,
717 LPSIZE32 size )
719 int dir, ascent, descent;
720 XCharStruct info;
722 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
723 if (!dc) return FALSE;
724 XTextExtents( dc->u.x.font.fstruct, str, count, &dir,
725 &ascent, &descent, &info );
726 size->cx = abs((info.width + dc->w.breakRem + count * dc->w.charExtra)
727 * dc->w.WndExtX / dc->w.VportExtX);
728 size->cy = abs((dc->u.x.font.fstruct->ascent+dc->u.x.font.fstruct->descent)
729 * dc->w.WndExtY / dc->w.VportExtY);
731 dprintf_font(stddeb,"GetTextExtentPoint(%08x '%*.*s' %d %p): returning %d,%d\n",
732 hdc, count, count, str, count, size, size->cx, size->cy );
733 return TRUE;
737 /***********************************************************************
738 * GetTextExtentPoint32W (GDI32.233)
740 BOOL32 GetTextExtentPoint32W( HDC32 hdc, LPCWSTR str, INT32 count,
741 LPSIZE32 size )
743 char *p = STRING32_DupUniToAnsi( str );
744 BOOL32 ret = GetTextExtentPoint32A( hdc, p, count, size );
745 free( p );
746 return ret;
750 /***********************************************************************
751 * GetTextMetrics16 (GDI.93)
753 BOOL16 GetTextMetrics16( HDC16 hdc, TEXTMETRIC16 *metrics )
755 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
756 if (!dc) return FALSE;
757 memcpy( metrics, &dc->u.x.font.metrics, sizeof(*metrics) );
759 metrics->tmAscent = abs( metrics->tmAscent
760 * dc->w.WndExtY / dc->w.VportExtY );
761 metrics->tmDescent = abs( metrics->tmDescent
762 * dc->w.WndExtY / dc->w.VportExtY );
763 metrics->tmHeight = metrics->tmAscent + metrics->tmDescent;
764 metrics->tmInternalLeading = abs( metrics->tmInternalLeading
765 * dc->w.WndExtY / dc->w.VportExtY );
766 metrics->tmExternalLeading = abs( metrics->tmExternalLeading
767 * dc->w.WndExtY / dc->w.VportExtY );
768 metrics->tmMaxCharWidth = abs( metrics->tmMaxCharWidth
769 * dc->w.WndExtX / dc->w.VportExtX );
770 metrics->tmAveCharWidth = abs( metrics->tmAveCharWidth
771 * dc->w.WndExtX / dc->w.VportExtX );
773 dprintf_font(stdnimp,"text metrics:\n
774 InternalLeading = %i
775 ExternalLeading = %i
776 MaxCharWidth = %i
777 Weight = %i
778 Italic = %i
779 Underlined = %i
780 StruckOut = %i
781 FirstChar = %i
782 LastChar = %i
783 DefaultChar = %i
784 BreakChar = %i
785 CharSet = %i
786 Overhang = %i
787 DigitizedAspectX = %i
788 DigitizedAspectY = %i
789 AveCharWidth = %i
790 MaxCharWidth = %i
791 Ascent = %i
792 Descent = %i
793 Height = %i\n",
794 metrics->tmInternalLeading,
795 metrics->tmExternalLeading,
796 metrics->tmMaxCharWidth,
797 metrics->tmWeight,
798 metrics->tmItalic,
799 metrics->tmUnderlined,
800 metrics->tmStruckOut,
801 metrics->tmFirstChar,
802 metrics->tmLastChar,
803 metrics->tmDefaultChar,
804 metrics->tmBreakChar,
805 metrics->tmCharSet,
806 metrics->tmOverhang,
807 metrics->tmDigitizedAspectX,
808 metrics->tmDigitizedAspectY,
809 metrics->tmAveCharWidth,
810 metrics->tmMaxCharWidth,
811 metrics->tmAscent,
812 metrics->tmDescent,
813 metrics->tmHeight);
815 return TRUE;
819 /***********************************************************************
820 * GetTextMetrics32A (GDI32.236)
822 BOOL32 GetTextMetrics32A( HDC32 hdc, TEXTMETRIC32A *metrics )
824 TEXTMETRIC16 tm;
825 if (!GetTextMetrics16( (HDC16)hdc, &tm )) return FALSE;
826 metrics->tmHeight = tm.tmHeight;
827 metrics->tmAscent = tm.tmAscent;
828 metrics->tmDescent = tm.tmDescent;
829 metrics->tmInternalLeading = tm.tmInternalLeading;
830 metrics->tmExternalLeading = tm.tmExternalLeading;
831 metrics->tmAveCharWidth = tm.tmAveCharWidth;
832 metrics->tmMaxCharWidth = tm.tmMaxCharWidth;
833 metrics->tmWeight = tm.tmWeight;
834 metrics->tmOverhang = tm.tmOverhang;
835 metrics->tmDigitizedAspectX = tm.tmDigitizedAspectX;
836 metrics->tmDigitizedAspectY = tm.tmDigitizedAspectY;
837 metrics->tmFirstChar = tm.tmFirstChar;
838 metrics->tmLastChar = tm.tmLastChar;
839 metrics->tmDefaultChar = tm.tmDefaultChar;
840 metrics->tmBreakChar = tm.tmBreakChar;
841 metrics->tmItalic = tm.tmItalic;
842 metrics->tmUnderlined = tm.tmUnderlined;
843 metrics->tmStruckOut = tm.tmStruckOut;
844 metrics->tmPitchAndFamily = tm.tmPitchAndFamily;
845 metrics->tmCharSet = tm.tmCharSet;
846 return TRUE;
850 /***********************************************************************
851 * GetTextMetrics32W (GDI32.237)
853 BOOL32 GetTextMetrics32W( HDC32 hdc, TEXTMETRIC32W *metrics )
855 TEXTMETRIC16 tm;
856 if (!GetTextMetrics16( (HDC16)hdc, &tm )) return FALSE;
857 metrics->tmHeight = tm.tmHeight;
858 metrics->tmAscent = tm.tmAscent;
859 metrics->tmDescent = tm.tmDescent;
860 metrics->tmInternalLeading = tm.tmInternalLeading;
861 metrics->tmExternalLeading = tm.tmExternalLeading;
862 metrics->tmAveCharWidth = tm.tmAveCharWidth;
863 metrics->tmMaxCharWidth = tm.tmMaxCharWidth;
864 metrics->tmWeight = tm.tmWeight;
865 metrics->tmOverhang = tm.tmOverhang;
866 metrics->tmDigitizedAspectX = tm.tmDigitizedAspectX;
867 metrics->tmDigitizedAspectY = tm.tmDigitizedAspectY;
868 metrics->tmFirstChar = tm.tmFirstChar;
869 metrics->tmLastChar = tm.tmLastChar;
870 metrics->tmDefaultChar = tm.tmDefaultChar;
871 metrics->tmBreakChar = tm.tmBreakChar;
872 metrics->tmItalic = tm.tmItalic;
873 metrics->tmUnderlined = tm.tmUnderlined;
874 metrics->tmStruckOut = tm.tmStruckOut;
875 metrics->tmPitchAndFamily = tm.tmPitchAndFamily;
876 metrics->tmCharSet = tm.tmCharSet;
877 return TRUE;
881 /***********************************************************************
882 * SetMapperFlags (GDI.349)
884 DWORD SetMapperFlags(HDC hDC, DWORD dwFlag)
886 dprintf_font(stdnimp,"SetmapperFlags(%04x, %08lX) // Empty Stub !\n",
887 hDC, dwFlag);
888 return 0L;
892 /***********************************************************************
893 * GetCharABCWidths (GDI.307)
895 BOOL GetCharABCWidths(HDC hdc, UINT wFirstChar, UINT wLastChar, LPABC16 lpABC)
898 /* No TrueType fonts in Wine so far */
900 fprintf(stdnimp,"STUB: GetCharABCWidths(%04x,%04x,%04x,%08x)\n",
901 hdc,wFirstChar,wLastChar,(unsigned)lpABC);
903 return FALSE;
907 /***********************************************************************
908 * GetCharWidth (GDI.350)
910 BOOL GetCharWidth(HDC hdc, WORD wFirstChar, WORD wLastChar, LPINT16 lpBuffer)
912 int i, j;
913 XFontStruct *xfont;
914 XCharStruct *cs, *def;
916 DC *dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC);
917 if (!dc) return FALSE;
918 xfont = dc->u.x.font.fstruct;
920 /* fixed font? */
921 if (xfont->per_char == NULL)
923 for (i = wFirstChar, j = 0; i <= wLastChar; i++, j++)
924 *(lpBuffer + j) = xfont->max_bounds.width;
925 return TRUE;
928 CI_GET_DEFAULT_INFO(xfont, def);
930 for (i = wFirstChar, j = 0; i <= wLastChar; i++, j++)
932 CI_GET_CHAR_INFO(xfont, i, def, cs);
933 *(lpBuffer + j) = cs ? cs->width : xfont->max_bounds.width;
934 if (*(lpBuffer + j) < 0)
935 *(lpBuffer + j) = 0;
937 return TRUE;
941 /***********************************************************************
942 * AddFontResource (GDI.119)
944 INT AddFontResource( LPCSTR str )
946 fprintf( stdnimp, "STUB: AddFontResource('%s')\n", str );
947 return 1;
951 /***********************************************************************
952 * RemoveFontResource (GDI.136)
954 BOOL RemoveFontResource( LPSTR str )
956 fprintf( stdnimp, "STUB: RemoveFontResource('%s')\n", str );
957 return TRUE;
961 /*************************************************************************
962 * ParseFontParms [internal]
964 int ParseFontParms(LPSTR lpFont, WORD wParmsNo, LPSTR lpRetStr, WORD wMaxSiz)
966 int i;
967 if (lpFont == NULL) return 0;
968 if (lpRetStr == NULL) return 0;
969 for (i = 0; (*lpFont != '\0' && i != wParmsNo); ) {
970 if (*lpFont == '-') i++;
971 lpFont++;
973 if (i == wParmsNo) {
974 if (*lpFont == '-') lpFont++;
975 wMaxSiz--;
976 for (i = 0; (*lpFont != '\0' && *lpFont != '-' && i < wMaxSiz); i++)
977 *(lpRetStr + i) = *lpFont++;
978 *(lpRetStr + i) = '\0';
979 return i;
981 else
982 lpRetStr[0] = '\0';
983 return 0;
987 /*************************************************************************
988 * InitFontsList [internal]
991 static int logfcmp(const void *a,const void *b)
993 return strcmp( (*(LPLOGFONT16 *)a)->lfFaceName,
994 (*(LPLOGFONT16 *)b)->lfFaceName );
997 void InitFontsList(void)
999 char str[32];
1000 char pattern[100];
1001 char *family, *weight, *charset;
1002 char **names;
1003 char slant, spacing;
1004 int i, count;
1005 LPLOGFONT16 lpNewFont;
1007 dprintf_font(stddeb,"InitFontsList !\n");
1009 weight = "medium";
1010 slant = 'r';
1011 spacing = '*';
1012 charset = "*";
1013 family = "*-*";
1015 sprintf( pattern, "-%s-%s-%c-normal-*-*-*-*-*-%c-*-%s",
1016 family, weight, slant, spacing, charset);
1017 names = XListFonts( display, pattern, MAX_FONTS, &count );
1018 dprintf_font(stddeb,"InitFontsList // count=%d \n", count);
1020 lpNewFont = malloc((sizeof(LOGFONT16)+LF_FACESIZE)*count);
1021 if (lpNewFont == NULL) {
1022 dprintf_font(stddeb,
1023 "InitFontsList // Error alloc new font structure !\n");
1024 XFreeFontNames(names);
1025 return;
1028 for (i = 0; i < count; i++) {
1029 dprintf_font(stddeb,"InitFontsList // names[%d]='%s' \n", i, names[i]);
1031 ParseFontParms(names[i], 2, str, sizeof(str));
1032 #if 0
1033 /* not necessary because new function FONT_ChkX11Family() */
1034 if (strcmp(str, "fixed") == 0) strcat(str, "sys");
1035 #endif
1036 AnsiUpper(str);
1037 strcpy(lpNewFont->lfFaceName, str);
1038 ParseFontParms(names[i], 8, str, sizeof(str));
1039 lpNewFont->lfHeight = atoi(str) / 10;
1040 ParseFontParms(names[i], 12, str, sizeof(str));
1041 lpNewFont->lfWidth = atoi(str) / 10;
1042 lpNewFont->lfEscapement = 0;
1043 lpNewFont->lfOrientation = 0;
1044 lpNewFont->lfWeight = FW_REGULAR;
1045 lpNewFont->lfItalic = 0;
1046 lpNewFont->lfUnderline = 0;
1047 lpNewFont->lfStrikeOut = 0;
1048 ParseFontParms(names[i], 13, str, sizeof(str));
1049 if (strcmp(str, "iso8859") == 0) {
1050 lpNewFont->lfCharSet = ANSI_CHARSET;
1051 } else {
1052 lpNewFont->lfCharSet = OEM_CHARSET;
1054 lpNewFont->lfOutPrecision = OUT_DEFAULT_PRECIS;
1055 lpNewFont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
1056 lpNewFont->lfQuality = DEFAULT_QUALITY;
1057 ParseFontParms(names[i], 11, str, sizeof(str));
1058 switch(str[0]) {
1059 case 'p':
1060 lpNewFont->lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
1061 break;
1062 case 'm':
1063 case 'c':
1064 lpNewFont->lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
1065 break;
1066 default:
1067 lpNewFont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
1068 break;
1070 dprintf_font( stddeb,
1071 "InitFontsList // lpNewFont->lfHeight=%d\n",
1072 lpNewFont->lfHeight );
1073 dprintf_font( stddeb,
1074 "InitFontsList // lpNewFont->lfWidth=%d\n",
1075 lpNewFont->lfWidth );
1076 dprintf_font( stddeb,
1077 "InitFontsList // lfFaceName='%s'\n",
1078 lpNewFont->lfFaceName );
1079 lpLogFontList[i] = lpNewFont;
1080 lpNewFont = (LPLOGFONT16)
1081 ((char *)lpNewFont + sizeof(LOGFONT16)+LF_FACESIZE);
1083 lpLogFontList[i] = NULL;
1085 qsort(lpLogFontList,count,sizeof(*lpLogFontList),logfcmp);
1086 XFreeFontNames(names);
1090 /*************************************************************************
1091 * EnumFonts [GDI.70]
1093 INT EnumFonts(HDC hDC, LPCSTR lpFaceName, FONTENUMPROC lpEnumFunc, LPARAM lpData)
1095 HANDLE hLog;
1096 HANDLE hMet;
1097 HFONT hFont;
1098 HFONT hOldFont;
1099 LPLOGFONT16 lpLogFont;
1100 LPTEXTMETRIC16 lptm;
1101 LPSTR lpOldName;
1102 char FaceName[LF_FACESIZE];
1103 int nRet = 0;
1104 int i;
1106 dprintf_font(stddeb,"EnumFonts(%04x, %p='%s', %08lx, %08lx)\n",
1107 hDC, lpFaceName, lpFaceName, (LONG)lpEnumFunc, lpData);
1108 if (lpEnumFunc == 0) return 0;
1109 hLog = GDI_HEAP_ALLOC( sizeof(LOGFONT16) + LF_FACESIZE );
1110 lpLogFont = (LPLOGFONT16) GDI_HEAP_LIN_ADDR(hLog);
1111 if (lpLogFont == NULL) {
1112 fprintf(stderr,"EnumFonts // can't alloc LOGFONT struct !\n");
1113 return 0;
1115 hMet = GDI_HEAP_ALLOC( sizeof(TEXTMETRIC16) );
1116 lptm = (LPTEXTMETRIC16) GDI_HEAP_LIN_ADDR(hMet);
1117 if (lptm == NULL) {
1118 GDI_HEAP_FREE(hLog);
1119 fprintf(stderr, "EnumFonts // can't alloc TEXTMETRIC struct !\n");
1120 return 0;
1122 if (lpFaceName != NULL) {
1123 strcpy(FaceName, lpFaceName);
1124 AnsiUpper(FaceName);
1126 lpOldName = NULL;
1128 if (lpLogFontList[0] == NULL) InitFontsList();
1129 for(i = 0; lpLogFontList[i] != NULL; i++) {
1130 if (lpFaceName == NULL) {
1131 if (lpOldName != NULL) {
1132 if (strcmp(lpOldName,lpLogFontList[i]->lfFaceName) == 0) continue;
1134 lpOldName = lpLogFontList[i]->lfFaceName;
1135 } else {
1136 if (strcmp(FaceName, lpLogFontList[i]->lfFaceName) != 0) continue;
1138 dprintf_font(stddeb,"EnumFonts // enum '%s' !\n", lpLogFontList[i]->lfFaceName);
1139 dprintf_font(stddeb,"EnumFonts // %p !\n", lpLogFontList[i]);
1140 memcpy(lpLogFont, lpLogFontList[i], sizeof(LOGFONT16) + LF_FACESIZE);
1141 hFont = CreateFontIndirect16(lpLogFont);
1142 hOldFont = SelectObject(hDC, hFont);
1143 GetTextMetrics16(hDC, lptm);
1144 SelectObject(hDC, hOldFont);
1145 DeleteObject(hFont);
1146 dprintf_font(stddeb,"EnumFonts // i=%d lpLogFont=%p lptm=%p\n", i, lpLogFont, lptm);
1147 nRet = CallEnumFontsProc((FARPROC16)lpEnumFunc, GDI_HEAP_SEG_ADDR(hLog),
1148 GDI_HEAP_SEG_ADDR(hMet), 0, (LONG)lpData );
1149 if (nRet == 0) {
1150 dprintf_font(stddeb,"EnumFonts // EnumEnd requested by application !\n");
1151 break;
1154 GDI_HEAP_FREE(hMet);
1155 GDI_HEAP_FREE(hLog);
1156 return nRet;
1160 /*************************************************************************
1161 * EnumFontFamilies [GDI.330]
1163 INT EnumFontFamilies(HDC hDC, LPCSTR lpszFamily, FONTENUMPROC lpEnumFunc, LPARAM lpData)
1165 HANDLE hLog;
1166 HANDLE hMet;
1167 HFONT hFont;
1168 HFONT hOldFont;
1169 LPENUMLOGFONT16 lpEnumLogFont;
1170 LPTEXTMETRIC16 lptm;
1171 LPSTR lpOldName;
1172 char FaceName[LF_FACESIZE];
1173 int nRet = 0;
1174 int i;
1176 dprintf_font(stddeb,"EnumFontFamilies(%04x, %p, %08lx, %08lx)\n",
1177 hDC, lpszFamily, (DWORD)lpEnumFunc, lpData);
1178 if (lpEnumFunc == 0) return 0;
1179 hLog = GDI_HEAP_ALLOC( sizeof(ENUMLOGFONT16) );
1180 lpEnumLogFont = (LPENUMLOGFONT16) GDI_HEAP_LIN_ADDR(hLog);
1181 if (lpEnumLogFont == NULL) {
1182 fprintf(stderr,"EnumFontFamilies // can't alloc LOGFONT struct !\n");
1183 return 0;
1185 hMet = GDI_HEAP_ALLOC( sizeof(TEXTMETRIC16) );
1186 lptm = (LPTEXTMETRIC16) GDI_HEAP_LIN_ADDR(hMet);
1187 if (lptm == NULL) {
1188 GDI_HEAP_FREE(hLog);
1189 fprintf(stderr,"EnumFontFamilies // can't alloc TEXTMETRIC struct !\n");
1190 return 0;
1192 lpOldName = NULL;
1193 if (lpszFamily != NULL) {
1194 strcpy(FaceName, lpszFamily);
1195 AnsiUpper(FaceName);
1197 if (lpLogFontList[0] == NULL) InitFontsList();
1198 for(i = 0; lpLogFontList[i] != NULL; i++) {
1199 if (lpszFamily == NULL) {
1200 if (lpOldName != NULL) {
1201 if (strcmp(lpOldName,lpLogFontList[i]->lfFaceName) == 0) continue;
1203 lpOldName = lpLogFontList[i]->lfFaceName;
1204 } else {
1205 if (strcmp(FaceName, lpLogFontList[i]->lfFaceName) != 0) continue;
1207 memcpy(lpEnumLogFont, lpLogFontList[i], sizeof(LOGFONT16));
1208 strcpy(lpEnumLogFont->elfFullName,"");
1209 strcpy(lpEnumLogFont->elfStyle,"");
1210 hFont = CreateFontIndirect16((LPLOGFONT16)lpEnumLogFont);
1211 hOldFont = SelectObject(hDC, hFont);
1212 GetTextMetrics16(hDC, lptm);
1213 SelectObject(hDC, hOldFont);
1214 DeleteObject(hFont);
1215 dprintf_font(stddeb, "EnumFontFamilies // i=%d lpLogFont=%p lptm=%p\n", i, lpEnumLogFont, lptm);
1217 nRet = CallEnumFontFamProc( (FARPROC16)lpEnumFunc,
1218 GDI_HEAP_SEG_ADDR(hLog),
1219 GDI_HEAP_SEG_ADDR(hMet),
1220 0, lpData );
1221 if (nRet == 0) {
1222 dprintf_font(stddeb,"EnumFontFamilies // EnumEnd requested by application !\n");
1223 break;
1226 GDI_HEAP_FREE(hMet);
1227 GDI_HEAP_FREE(hLog);
1228 return nRet;
1231 /*************************************************************************
1232 * GetRasterizerCaps [GDI.313]
1235 BOOL GetRasterizerCaps(LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
1237 /* This is not much more than a dummy */
1238 RASTERIZER_STATUS rs;
1240 rs.nSize = sizeof(rs);
1241 rs.wFlags = 0;
1242 rs.nLanguageID = 0;
1243 return True;
1246 /*************************************************************************
1247 * GetKerningPairs [GDI.332]
1249 int GetKerningPairs(HDC hDC,int cPairs,LPKERNINGPAIR16 lpKerningPairs)
1251 /* This has to be dealt with when proper font handling is in place
1253 * At this time kerning is ignored (set to 0)
1256 int i;
1257 fprintf(stdnimp,"GetKerningPairs: almost empty stub!\n");
1258 for (i = 0; i < cPairs; i++) lpKerningPairs[i].iKernAmount = 0;
1259 return 0;