/* * GDI font objects * * Copyright 1993 Alexandre Julliard * * Enhacements by Juergen Marquardt 1996 * * Implementation of a second font cache which * will be updated dynamically */ #include #include #include #include #include "font.h" #include "metafile.h" #include "callback.h" #include "options.h" #include "string32.h" #include "xmalloc.h" #include "stddebug.h" #include "debug.h" #define FONTCACHE 32 /* dynamic font cache size */ #define MAX_FONTS 256 static LPLOGFONT16 lpLogFontList[MAX_FONTS+1]; static int ParseFontParms(LPSTR lpFont, WORD wParmsNo, LPSTR lpRetStr, WORD wMaxSiz); #define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \ (((cs)->rbearing|(cs)->lbearing| \ (cs)->ascent|(cs)->descent) == 0)) /* * CI_GET_CHAR_INFO - return the charinfo struct for the indicated 8bit * character. If the character is in the column and exists, then return the * appropriate metrics (note that fonts with common per-character metrics will * return min_bounds). If none of these hold true, try again with the default * char. */ #define CI_GET_CHAR_INFO(fs,col,def,cs) \ { \ cs = def; \ if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ if (fs->per_char == NULL) { \ cs = &fs->min_bounds; \ } else { \ cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \ if (CI_NONEXISTCHAR(cs)) cs = def; \ } \ } \ } #define CI_GET_DEFAULT_INFO(fs,cs) \ CI_GET_CHAR_INFO(fs, fs->default_char, NULL, cs) struct FontStructure { char *window; char *x11; } FontNames[32]; int FontSize; /*********************************************************************** * FONT_Init */ BOOL FONT_Init( void ) { char temp[1024]; LPSTR ptr; int i; if (PROFILE_GetWineIniString( "fonts", NULL, "*", temp, sizeof(temp) ) > 2 ) { for( ptr = temp, i = 1; strlen(ptr) != 0; ptr += strlen(ptr) + 1 ) if( strcmp( ptr, "default" ) ) FontNames[i++].window = xstrdup( ptr ); FontSize = i; for( i = 1; i < FontSize; i++ ) { PROFILE_GetWineIniString( "fonts", FontNames[i].window, "*", temp, sizeof(temp) ); FontNames[i].x11 = xstrdup( temp ); } PROFILE_GetWineIniString( "fonts", "default", "*", temp, sizeof(temp) ); FontNames[0].x11 = xstrdup( temp ); } else { FontNames[0].window = NULL; FontNames[0].x11 = "*-helvetica"; FontNames[1].window = "ms sans serif"; FontNames[1].x11 = "*-helvetica"; FontNames[2].window = "ms serif"; FontNames[2].x11 = "*-times"; FontNames[3].window = "fixedsys"; FontNames[3].x11 = "*-fixed"; FontNames[4].window = "arial"; FontNames[4].x11 = "*-helvetica"; FontNames[5].window = "helv"; FontNames[5].x11 = "*-helvetica"; FontNames[6].window = "roman"; FontNames[6].x11 = "*-times"; FontSize = 7; } return TRUE; } /*********************************************************************** * FONT_ChkX11Family * * returns a valid X11 equivalent if a Windows face name * is like a X11 family - or NULL if translation is needed */ static char *FONT_ChkX11Family(char *winFaceName ) { static char x11fam[32+2]; /* will be returned */ int i; for(i = 0; lpLogFontList[i] != NULL; i++) if( !lstrcmpi32A(winFaceName, lpLogFontList[i]->lfFaceName) ) { strcpy(x11fam,"*-"); return strcat(x11fam,winFaceName); } return NULL; /* a FONT_TranslateName() call is needed */ } /*********************************************************************** * FONT_TranslateName * * Translate a Windows face name to its X11 equivalent. * This will probably have to be customizable. */ static const char *FONT_TranslateName( char *winFaceName ) { int i; for (i = 1; i < FontSize; i ++) if( !strcmp( winFaceName, FontNames[i].window ) ) { dprintf_font(stddeb, "---- Mapped %s to %s\n", winFaceName, FontNames[i].x11 ); return FontNames[i].x11; } return FontNames[0].x11; } /*********************************************************************** * FONT_MatchFont * * Find a X font matching the logical font. */ static XFontStruct * FONT_MatchFont( LOGFONT16 * font, DC * dc ) { char pattern[100]; const char *family, *weight, *charset; char **names; char slant, oldspacing, spacing; int width, height, oldheight, count; XFontStruct * fontStruct; dprintf_font(stddeb, "FONT_MatchFont(H,W = %d,%d; Weight = %d; Italic = %d; FaceName = '%s'\n", font->lfHeight, font->lfWidth, font->lfWeight, font->lfItalic, font->lfFaceName); weight = (font->lfWeight > 550) ? "bold" : "medium"; slant = font->lfItalic ? 'i' : 'r'; if (font->lfHeight == -1) height = 0; else height = font->lfHeight * dc->w.VportExtX / dc->w.WndExtX; if (height == 0) height = 120; /* Default height = 12 */ else if (height < 0) { /* If height is negative, it means the height of the characters */ /* *without* the internal leading. So we adjust it a bit to */ /* compensate. 5/4 seems to give good results for small fonts. */ /* * J.M.: This causes wrong font size for bigger fonts e.g. in Winword & Write height = 10 * (-height * 9 / 8); * may be we have to use an non linear function */ /* assume internal leading is 2 pixels. Else small fonts will become * very small. */ height = (height-2) * -10; } else height *= 10; width = 10 * (font->lfWidth * dc->w.VportExtY / dc->w.WndExtY); if (width < 0) { dprintf_font( stddeb, "FONT_MatchFont: negative width %d(%d)\n", width, font->lfWidth ); width = -width; } spacing = (font->lfPitchAndFamily & FIXED_PITCH) ? 'm' : (font->lfPitchAndFamily & VARIABLE_PITCH) ? 'p' : '*'; charset = (font->lfCharSet == ANSI_CHARSET) ? "iso8859-1" : "*-*"; if (*font->lfFaceName) { family = FONT_ChkX11Family(font->lfFaceName); /*--do _not_ translate if lfFaceName is family from X11 A.K.*/ if (!family) family = FONT_TranslateName( font->lfFaceName ); /* FIX ME: I don't if that's correct but it works J.M. */ spacing = '*'; } else switch(font->lfPitchAndFamily & 0xf0) { case FF_ROMAN: family = FONT_TranslateName( "roman" ); break; case FF_SWISS: family = FONT_TranslateName( "swiss" ); break; case FF_MODERN: family = FONT_TranslateName( "modern" ); break; case FF_SCRIPT: family = FONT_TranslateName( "script" ); break; case FF_DECORATIVE: family = FONT_TranslateName( "decorative" ); break; default: family = "*-*"; break; } oldheight = height; oldspacing = spacing; while (TRUE) { /* Width==0 seems not to be a valid wildcard on SGI's, using * instead */ if ( width == 0 ) sprintf( pattern, "-%s-%s-%c-normal-*-*-%d-*-*-%c-*-%s", family, weight, slant, height, spacing, charset); else sprintf( pattern, "-%s-%s-%c-normal-*-*-%d-*-*-%c-%d-%s", family, weight, slant, height, spacing, width, charset); dprintf_font(stddeb, "FONT_MatchFont: '%s'\n", pattern ); names = XListFonts( display, pattern, 1, &count ); if (count > 0) break; if (spacing == 'm') /* try 'c' if no 'm' found */ { spacing = 'c'; continue; } else if (spacing == 'p') /* try '*' if no 'p' found */ { spacing = '*'; continue; } spacing = oldspacing; height -= 10; if (height < 10) { if (slant == 'i') { /* try oblique if no italic font */ slant = 'o'; height = oldheight; continue; } if (spacing == 'm' && strcmp(family, "*-*") != 0) { /* If a fixed spacing font could not be found, ignore * the family */ family = "*-*"; height = oldheight; continue; } fprintf(stderr, "FONT_MatchFont(%s) : returning NULL\n", pattern); return NULL; } } dprintf_font(stddeb," Found '%s'\n", *names ); if (!*font->lfFaceName) ParseFontParms(*names, 2, font->lfFaceName , LF_FACESIZE-1); /* we need a font name for function GetTextFace() even if there isn't one ;-) */ AnsiUpper(font->lfFaceName); fontStruct = XLoadQueryFont( display, *names ); XFreeFontNames( names ); return fontStruct; } /*********************************************************************** * FONT_GetMetrics */ void FONT_GetMetrics( LOGFONT16 * logfont, XFontStruct * xfont, TEXTMETRIC16 * metrics ) { int average, i, count; unsigned long prop; metrics->tmAscent = xfont->ascent; metrics->tmDescent = xfont->descent; metrics->tmHeight = xfont->ascent + xfont->descent; metrics->tmInternalLeading = 0; if (XGetFontProperty( xfont, XA_X_HEIGHT, &prop )) metrics->tmInternalLeading = xfont->ascent - (short)prop; metrics->tmExternalLeading = 0; metrics->tmMaxCharWidth = xfont->max_bounds.width; metrics->tmWeight = logfont->lfWeight; metrics->tmItalic = logfont->lfItalic; metrics->tmUnderlined = logfont->lfUnderline; metrics->tmStruckOut = logfont->lfStrikeOut; metrics->tmFirstChar = xfont->min_char_or_byte2; metrics->tmLastChar = xfont->max_char_or_byte2; metrics->tmDefaultChar = xfont->default_char; metrics->tmBreakChar = ' '; metrics->tmCharSet = logfont->lfCharSet; metrics->tmOverhang = 0; metrics->tmDigitizedAspectX = 1; metrics->tmDigitizedAspectY = 1; metrics->tmPitchAndFamily = (logfont->lfPitchAndFamily&0xf0)|TMPF_DEVICE; if (logfont->lfPitchAndFamily & FIXED_PITCH) metrics->tmPitchAndFamily |= TMPF_FIXED_PITCH; if (!xfont->per_char) average = metrics->tmMaxCharWidth; else { XCharStruct * charPtr = xfont->per_char; average = count = 0; for (i = metrics->tmFirstChar; i <= metrics->tmLastChar; i++) { if (!CI_NONEXISTCHAR( charPtr )) { average += charPtr->width; count++; } charPtr++; } if (count) average = (average + count/2) / count; } metrics->tmAveCharWidth = average; } /*********************************************************************** * GetGlyphOutLine (GDI.309) */ DWORD GetGlyphOutLine(HDC hdc, UINT uChar, UINT fuFormat, LPGLYPHMETRICS lpgm, DWORD cbBuffer, LPSTR lpBuffer, LPMAT2 lpmat2) { fprintf( stdnimp,"GetGlyphOutLine(%04x, '%c', %04x, %p, %ld, %p, %p) // - empty stub!\n", hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 ); return (DWORD)-1; /* failure */ } /*********************************************************************** * CreateScalableFontResource (GDI.310) */ BOOL CreateScalableFontResource( UINT fHidden,LPSTR lpszResourceFile, LPSTR lpszFontFile, LPSTR lpszCurrentPath ) { /* fHidden=1 - only visible for the calling app, read-only, not * enumbered with EnumFonts/EnumFontFamilies * lpszCurrentPath can be NULL */ fprintf(stdnimp,"CreateScalableFontResource(%d,%s,%s,%s) // empty stub!\n", fHidden, lpszResourceFile, lpszFontFile, lpszCurrentPath ); return FALSE; /* create failed */ } /*********************************************************************** * CreateFontIndirect16 (GDI.57) */ HFONT16 CreateFontIndirect16( const LOGFONT16 *font ) { FONTOBJ * fontPtr; HFONT16 hfont; if (!font) { fprintf(stderr,"CreateFontIndirect: font is NULL : returning NULL\n"); return 0; } hfont = GDI_AllocObject( sizeof(FONTOBJ), FONT_MAGIC ); if (!hfont) return 0; fontPtr = (FONTOBJ *) GDI_HEAP_LIN_ADDR( hfont ); memcpy( &fontPtr->logfont, font, sizeof(LOGFONT16) ); AnsiLower( fontPtr->logfont.lfFaceName ); dprintf_font(stddeb,"CreateFontIndirect(%p (%d,%d)); return %04x\n", font, font->lfHeight, font->lfWidth, hfont); return hfont; } /*********************************************************************** * CreateFontIndirect32A (GDI32.44) */ HFONT32 CreateFontIndirect32A( const LOGFONT32A *font ) { LOGFONT16 font16; font16.lfHeight = (INT16)font->lfHeight; font16.lfWidth = (INT16)font->lfWidth; font16.lfEscapement = (INT16)font->lfEscapement; font16.lfOrientation = (INT16)font->lfOrientation; font16.lfWeight = (INT16)font->lfWeight; font16.lfItalic = font->lfItalic; font16.lfUnderline = font->lfUnderline; font16.lfStrikeOut = font->lfStrikeOut; font16.lfCharSet = font->lfCharSet; font16.lfOutPrecision = font->lfOutPrecision; font16.lfClipPrecision = font->lfClipPrecision; font16.lfQuality = font->lfQuality; font16.lfPitchAndFamily = font->lfPitchAndFamily; lstrcpyn32A( font16.lfFaceName, font->lfFaceName, LF_FACESIZE ); return CreateFontIndirect16( &font16 ); } /*********************************************************************** * CreateFontIndirect32W (GDI32.45) */ HFONT32 CreateFontIndirect32W( const LOGFONT32W *font ) { LOGFONT16 font16; font16.lfHeight = (INT16)font->lfHeight; font16.lfWidth = (INT16)font->lfWidth; font16.lfEscapement = (INT16)font->lfEscapement; font16.lfOrientation = (INT16)font->lfOrientation; font16.lfWeight = (INT16)font->lfWeight; font16.lfItalic = font->lfItalic; font16.lfUnderline = font->lfUnderline; font16.lfStrikeOut = font->lfStrikeOut; font16.lfCharSet = font->lfCharSet; font16.lfOutPrecision = font->lfOutPrecision; font16.lfClipPrecision = font->lfClipPrecision; font16.lfQuality = font->lfQuality; font16.lfPitchAndFamily = font->lfPitchAndFamily; lstrcpynWtoA( font16.lfFaceName, font->lfFaceName, LF_FACESIZE ); return CreateFontIndirect16( &font16 ); } /*********************************************************************** * CreateFont (GDI.56) */ HFONT CreateFont( INT height, INT width, INT esc, INT orient, INT weight, BYTE italic, BYTE underline, BYTE strikeout, BYTE charset, BYTE outpres, BYTE clippres, BYTE quality, BYTE pitch, LPCSTR name ) { LOGFONT16 logfont = {height, width, esc, orient, weight, italic, underline, strikeout, charset, outpres, clippres, quality, pitch, }; dprintf_font(stddeb,"CreateFont(%d,%d)\n", height, width); if (name) lstrcpyn32A(logfont.lfFaceName,name,sizeof(logfont.lfFaceName)); else logfont.lfFaceName[0] = '\0'; return CreateFontIndirect16( &logfont ); } /*********************************************************************** * FONT_GetObject */ int FONT_GetObject( FONTOBJ * font, int count, LPSTR buffer ) { if (count > sizeof(LOGFONT16)) count = sizeof(LOGFONT16); memcpy( buffer, &font->logfont, count ); return count; } /*********************************************************************** * FONT_SelectObject */ HFONT FONT_SelectObject( DC * dc, HFONT hfont, FONTOBJ * font ) { static X_PHYSFONT stockFonts[LAST_STOCK_FONT-FIRST_STOCK_FONT+1]; static struct { HFONT id; LOGFONT16 logfont; int access; int used; X_PHYSFONT cacheFont; } cacheFonts[FONTCACHE], *cacheFontsMin; int i; X_PHYSFONT * stockPtr; HFONT prevHandle = dc->w.hFont; XFontStruct * fontStruct; dprintf_font(stddeb,"FONT_SelectObject(%p, %04x, %p)\n", dc, hfont, font); #if 0 /* From the code in SelectObject, this can not happen */ /* Load font if necessary */ if (!font) { HFONT hnewfont; hnewfont = CreateFont(10, 7, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, 0, 0, DEFAULT_QUALITY, FF_DONTCARE, "*" ); font = (FONTOBJ *) GDI_HEAP_LIN_ADDR( hnewfont ); } #endif if (dc->header.wMagic == METAFILE_DC_MAGIC) if (MF_CreateFontIndirect(dc, hfont, &(font->logfont))) return prevHandle; else return 0; if ((hfont >= FIRST_STOCK_FONT) && (hfont <= LAST_STOCK_FONT)) stockPtr = &stockFonts[hfont - FIRST_STOCK_FONT]; else { stockPtr = NULL; /* * Ok, It's not a stock font but * may be it's cached in dynamic cache */ for(i=0; ilogfont), sizeof(LOGFONT16))) { /* No: remove handle id from dynamic font cache */ cacheFonts[i].access=0; cacheFonts[i].used=0; cacheFonts[i].id=0; /* may be there is an unused handle which contains the font */ for(i=0; ilogfont), sizeof(LOGFONT16)))== 0) { /* got it load from cache and set new handle id */ stockPtr = &cacheFonts[i].cacheFont; cacheFonts[i].access=1; cacheFonts[i].used=1; cacheFonts[i].id=hfont; dprintf_font(stddeb,"FONT_SelectObject: got font from unused handle\n"); break; } } } else { /* Yes: load from dynamic font cache */ stockPtr = &cacheFonts[i].cacheFont; cacheFonts[i].access++; cacheFonts[i].used++; } break; } } if (!stockPtr || !stockPtr->fstruct) { if (!(fontStruct = FONT_MatchFont( &font->logfont, dc ))) { /* If it is not a stock font, we can simply return 0 */ if (!stockPtr) return 0; /* Otherwise we must try to find a substitute */ dprintf_font(stddeb,"Loading font 'fixed' for %04x\n", hfont ); font->logfont.lfPitchAndFamily &= ~VARIABLE_PITCH; font->logfont.lfPitchAndFamily |= FIXED_PITCH; fontStruct = XLoadQueryFont( display, "fixed" ); if (!fontStruct) { fprintf( stderr, "No system font could be found. Please check your font path.\n" ); exit( 1 ); } } } else { fontStruct = stockPtr->fstruct; dprintf_font(stddeb, "FONT_SelectObject: Loaded font from cache %04x %p\n", hfont, fontStruct ); } /* Unuse previous font */ for (i=0; i < FONTCACHE; i++) { if (cacheFonts[i].id == prevHandle) { if(cacheFonts[i].used == 0) fprintf(stderr, "Trying to decrement a use count of 0.\n"); else cacheFonts[i].used--; } } /* Store font */ dc->w.hFont = hfont; if (stockPtr) { if (!stockPtr->fstruct) { stockPtr->fstruct = fontStruct; FONT_GetMetrics( &font->logfont, fontStruct, &stockPtr->metrics ); } memcpy( &dc->u.x.font, stockPtr, sizeof(*stockPtr) ); } else { /* * Check in cacheFont */ cacheFontsMin=NULL; for (i=0; i < FONTCACHE; i++) { if (cacheFonts[i].used==0) if ((!cacheFontsMin) || ((cacheFontsMin) && (cacheFontsMin->access > cacheFonts[i].access))) cacheFontsMin=&cacheFonts[i]; } if (!cacheFontsMin) { fprintf(stderr,"No unused font cache entry !!!!\n" ); return prevHandle; } if (cacheFontsMin->id!=0) { dprintf_font(stddeb, "FONT_SelectObject: Freeing %04x \n",cacheFontsMin->id ); XFreeFont( display, cacheFontsMin->cacheFont.fstruct ); } cacheFontsMin->cacheFont.fstruct = fontStruct; FONT_GetMetrics( &font->logfont, fontStruct, &cacheFontsMin->cacheFont.metrics ); cacheFontsMin->access=1; cacheFontsMin->used=1; cacheFontsMin->id=hfont; memcpy( &dc->u.x.font, &(cacheFontsMin->cacheFont), sizeof(cacheFontsMin->cacheFont) ); memcpy(&cacheFontsMin->logfont,&(font->logfont), sizeof(LOGFONT16)); } return prevHandle; } /*********************************************************************** * GetTextCharacterExtra (GDI.89) */ short GetTextCharacterExtra( HDC hdc ) { DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return 0; return abs( (dc->w.charExtra * dc->w.WndExtX + dc->w.VportExtX / 2) / dc->w.VportExtX ); } /*********************************************************************** * SetTextCharacterExtra (GDI.8) */ short SetTextCharacterExtra( HDC hdc, short extra ) { short prev; DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return 0; extra = (extra * dc->w.VportExtX + dc->w.WndExtX / 2) / dc->w.WndExtX; prev = dc->w.charExtra; dc->w.charExtra = abs(extra); return (prev * dc->w.WndExtX + dc->w.VportExtX / 2) / dc->w.VportExtX; } /*********************************************************************** * SetTextJustification (GDI.10) */ short SetTextJustification( HDC hdc, short extra, short breaks ) { DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return 0; extra = abs((extra * dc->w.VportExtX + dc->w.WndExtX / 2) / dc->w.WndExtX); if (!extra) breaks = 0; dc->w.breakTotalExtra = extra; dc->w.breakCount = breaks; if (breaks) { dc->w.breakExtra = extra / breaks; dc->w.breakRem = extra - (dc->w.breakCount * dc->w.breakExtra); } else { dc->w.breakExtra = 0; dc->w.breakRem = 0; } return 1; } /*********************************************************************** * GetTextFace (GDI.92) */ INT GetTextFace( HDC hdc, INT count, LPSTR name ) { FONTOBJ *font; DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return 0; if (!(font = (FONTOBJ *) GDI_GetObjPtr( dc->w.hFont, FONT_MAGIC ))) return 0; lstrcpyn32A( name, font->logfont.lfFaceName, count ); return strlen(name); } /*********************************************************************** * GetTextExtent (GDI.91) */ DWORD GetTextExtent( HDC hdc, LPCSTR str, short count ) { SIZE16 size; if (!GetTextExtentPoint16( hdc, str, count, &size )) return 0; return MAKELONG( size.cx, size.cy ); } /*********************************************************************** * GetTextExtentPoint16 (GDI.471) */ BOOL16 GetTextExtentPoint16( HDC16 hdc, LPCSTR str, INT16 count, LPSIZE16 size) { SIZE32 size32; BOOL32 ret = GetTextExtentPoint32A( hdc, str, count, &size32 ); CONV_SIZE32TO16( &size32, size ); return (BOOL16)ret; } /*********************************************************************** * GetTextExtentPoint32A (GDI32.232) */ BOOL32 GetTextExtentPoint32A( HDC32 hdc, LPCSTR str, INT32 count, LPSIZE32 size ) { int dir, ascent, descent; XCharStruct info; DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return FALSE; XTextExtents( dc->u.x.font.fstruct, str, count, &dir, &ascent, &descent, &info ); size->cx = abs((info.width + dc->w.breakRem + count * dc->w.charExtra) * dc->w.WndExtX / dc->w.VportExtX); size->cy = abs((dc->u.x.font.fstruct->ascent+dc->u.x.font.fstruct->descent) * dc->w.WndExtY / dc->w.VportExtY); dprintf_font(stddeb,"GetTextExtentPoint(%08x '%*.*s' %d %p): returning %d,%d\n", hdc, count, count, str, count, size, size->cx, size->cy ); return TRUE; } /*********************************************************************** * GetTextExtentPoint32W (GDI32.233) */ BOOL32 GetTextExtentPoint32W( HDC32 hdc, LPCWSTR str, INT32 count, LPSIZE32 size ) { char *p = STRING32_DupUniToAnsi( str ); BOOL32 ret = GetTextExtentPoint32A( hdc, p, count, size ); free( p ); return ret; } /*********************************************************************** * GetTextMetrics16 (GDI.93) */ BOOL16 GetTextMetrics16( HDC16 hdc, TEXTMETRIC16 *metrics ) { DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return FALSE; memcpy( metrics, &dc->u.x.font.metrics, sizeof(*metrics) ); metrics->tmAscent = abs( metrics->tmAscent * dc->w.WndExtY / dc->w.VportExtY ); metrics->tmDescent = abs( metrics->tmDescent * dc->w.WndExtY / dc->w.VportExtY ); metrics->tmHeight = metrics->tmAscent + metrics->tmDescent; metrics->tmInternalLeading = abs( metrics->tmInternalLeading * dc->w.WndExtY / dc->w.VportExtY ); metrics->tmExternalLeading = abs( metrics->tmExternalLeading * dc->w.WndExtY / dc->w.VportExtY ); metrics->tmMaxCharWidth = abs( metrics->tmMaxCharWidth * dc->w.WndExtX / dc->w.VportExtX ); metrics->tmAveCharWidth = abs( metrics->tmAveCharWidth * dc->w.WndExtX / dc->w.VportExtX ); dprintf_font(stdnimp,"text metrics:\n InternalLeading = %i ExternalLeading = %i MaxCharWidth = %i Weight = %i Italic = %i Underlined = %i StruckOut = %i FirstChar = %i LastChar = %i DefaultChar = %i BreakChar = %i CharSet = %i Overhang = %i DigitizedAspectX = %i DigitizedAspectY = %i AveCharWidth = %i MaxCharWidth = %i Ascent = %i Descent = %i Height = %i\n", metrics->tmInternalLeading, metrics->tmExternalLeading, metrics->tmMaxCharWidth, metrics->tmWeight, metrics->tmItalic, metrics->tmUnderlined, metrics->tmStruckOut, metrics->tmFirstChar, metrics->tmLastChar, metrics->tmDefaultChar, metrics->tmBreakChar, metrics->tmCharSet, metrics->tmOverhang, metrics->tmDigitizedAspectX, metrics->tmDigitizedAspectY, metrics->tmAveCharWidth, metrics->tmMaxCharWidth, metrics->tmAscent, metrics->tmDescent, metrics->tmHeight); return TRUE; } /*********************************************************************** * GetTextMetrics32A (GDI32.236) */ BOOL32 GetTextMetrics32A( HDC32 hdc, TEXTMETRIC32A *metrics ) { TEXTMETRIC16 tm; if (!GetTextMetrics16( (HDC16)hdc, &tm )) return FALSE; metrics->tmHeight = tm.tmHeight; metrics->tmAscent = tm.tmAscent; metrics->tmDescent = tm.tmDescent; metrics->tmInternalLeading = tm.tmInternalLeading; metrics->tmExternalLeading = tm.tmExternalLeading; metrics->tmAveCharWidth = tm.tmAveCharWidth; metrics->tmMaxCharWidth = tm.tmMaxCharWidth; metrics->tmWeight = tm.tmWeight; metrics->tmOverhang = tm.tmOverhang; metrics->tmDigitizedAspectX = tm.tmDigitizedAspectX; metrics->tmDigitizedAspectY = tm.tmDigitizedAspectY; metrics->tmFirstChar = tm.tmFirstChar; metrics->tmLastChar = tm.tmLastChar; metrics->tmDefaultChar = tm.tmDefaultChar; metrics->tmBreakChar = tm.tmBreakChar; metrics->tmItalic = tm.tmItalic; metrics->tmUnderlined = tm.tmUnderlined; metrics->tmStruckOut = tm.tmStruckOut; metrics->tmPitchAndFamily = tm.tmPitchAndFamily; metrics->tmCharSet = tm.tmCharSet; return TRUE; } /*********************************************************************** * GetTextMetrics32W (GDI32.237) */ BOOL32 GetTextMetrics32W( HDC32 hdc, TEXTMETRIC32W *metrics ) { TEXTMETRIC16 tm; if (!GetTextMetrics16( (HDC16)hdc, &tm )) return FALSE; metrics->tmHeight = tm.tmHeight; metrics->tmAscent = tm.tmAscent; metrics->tmDescent = tm.tmDescent; metrics->tmInternalLeading = tm.tmInternalLeading; metrics->tmExternalLeading = tm.tmExternalLeading; metrics->tmAveCharWidth = tm.tmAveCharWidth; metrics->tmMaxCharWidth = tm.tmMaxCharWidth; metrics->tmWeight = tm.tmWeight; metrics->tmOverhang = tm.tmOverhang; metrics->tmDigitizedAspectX = tm.tmDigitizedAspectX; metrics->tmDigitizedAspectY = tm.tmDigitizedAspectY; metrics->tmFirstChar = tm.tmFirstChar; metrics->tmLastChar = tm.tmLastChar; metrics->tmDefaultChar = tm.tmDefaultChar; metrics->tmBreakChar = tm.tmBreakChar; metrics->tmItalic = tm.tmItalic; metrics->tmUnderlined = tm.tmUnderlined; metrics->tmStruckOut = tm.tmStruckOut; metrics->tmPitchAndFamily = tm.tmPitchAndFamily; metrics->tmCharSet = tm.tmCharSet; return TRUE; } /*********************************************************************** * SetMapperFlags (GDI.349) */ DWORD SetMapperFlags(HDC hDC, DWORD dwFlag) { dprintf_font(stdnimp,"SetmapperFlags(%04x, %08lX) // Empty Stub !\n", hDC, dwFlag); return 0L; } /*********************************************************************** * GetCharABCWidths (GDI.307) */ BOOL GetCharABCWidths(HDC hdc, UINT wFirstChar, UINT wLastChar, LPABC16 lpABC) { /* No TrueType fonts in Wine so far */ fprintf(stdnimp,"STUB: GetCharABCWidths(%04x,%04x,%04x,%08x)\n", hdc,wFirstChar,wLastChar,(unsigned)lpABC); return FALSE; } /*********************************************************************** * GetCharWidth (GDI.350) */ BOOL GetCharWidth(HDC hdc, WORD wFirstChar, WORD wLastChar, LPINT16 lpBuffer) { int i, j; XFontStruct *xfont; XCharStruct *cs, *def; DC *dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC); if (!dc) return FALSE; xfont = dc->u.x.font.fstruct; /* fixed font? */ if (xfont->per_char == NULL) { for (i = wFirstChar, j = 0; i <= wLastChar; i++, j++) *(lpBuffer + j) = xfont->max_bounds.width; return TRUE; } CI_GET_DEFAULT_INFO(xfont, def); for (i = wFirstChar, j = 0; i <= wLastChar; i++, j++) { CI_GET_CHAR_INFO(xfont, i, def, cs); *(lpBuffer + j) = cs ? cs->width : xfont->max_bounds.width; if (*(lpBuffer + j) < 0) *(lpBuffer + j) = 0; } return TRUE; } /*********************************************************************** * AddFontResource (GDI.119) */ INT AddFontResource( LPCSTR str ) { fprintf( stdnimp, "STUB: AddFontResource('%s')\n", str ); return 1; } /*********************************************************************** * RemoveFontResource (GDI.136) */ BOOL RemoveFontResource( LPSTR str ) { fprintf( stdnimp, "STUB: RemoveFontResource('%s')\n", str ); return TRUE; } /************************************************************************* * ParseFontParms [internal] */ int ParseFontParms(LPSTR lpFont, WORD wParmsNo, LPSTR lpRetStr, WORD wMaxSiz) { int i; if (lpFont == NULL) return 0; if (lpRetStr == NULL) return 0; for (i = 0; (*lpFont != '\0' && i != wParmsNo); ) { if (*lpFont == '-') i++; lpFont++; } if (i == wParmsNo) { if (*lpFont == '-') lpFont++; wMaxSiz--; for (i = 0; (*lpFont != '\0' && *lpFont != '-' && i < wMaxSiz); i++) *(lpRetStr + i) = *lpFont++; *(lpRetStr + i) = '\0'; return i; } else lpRetStr[0] = '\0'; return 0; } /************************************************************************* * InitFontsList [internal] */ static int logfcmp(const void *a,const void *b) { return strcmp( (*(LPLOGFONT16 *)a)->lfFaceName, (*(LPLOGFONT16 *)b)->lfFaceName ); } void InitFontsList(void) { char str[32]; char pattern[100]; char *family, *weight, *charset; char **names; char slant, spacing; int i, count; LPLOGFONT16 lpNewFont; dprintf_font(stddeb,"InitFontsList !\n"); weight = "medium"; slant = 'r'; spacing = '*'; charset = "*"; family = "*-*"; sprintf( pattern, "-%s-%s-%c-normal-*-*-*-*-*-%c-*-%s", family, weight, slant, spacing, charset); names = XListFonts( display, pattern, MAX_FONTS, &count ); dprintf_font(stddeb,"InitFontsList // count=%d \n", count); lpNewFont = malloc((sizeof(LOGFONT16)+LF_FACESIZE)*count); if (lpNewFont == NULL) { dprintf_font(stddeb, "InitFontsList // Error alloc new font structure !\n"); XFreeFontNames(names); return; } for (i = 0; i < count; i++) { dprintf_font(stddeb,"InitFontsList // names[%d]='%s' \n", i, names[i]); ParseFontParms(names[i], 2, str, sizeof(str)); #if 0 /* not necessary because new function FONT_ChkX11Family() */ if (strcmp(str, "fixed") == 0) strcat(str, "sys"); #endif AnsiUpper(str); strcpy(lpNewFont->lfFaceName, str); ParseFontParms(names[i], 8, str, sizeof(str)); lpNewFont->lfHeight = atoi(str) / 10; ParseFontParms(names[i], 12, str, sizeof(str)); lpNewFont->lfWidth = atoi(str) / 10; lpNewFont->lfEscapement = 0; lpNewFont->lfOrientation = 0; lpNewFont->lfWeight = FW_REGULAR; lpNewFont->lfItalic = 0; lpNewFont->lfUnderline = 0; lpNewFont->lfStrikeOut = 0; ParseFontParms(names[i], 13, str, sizeof(str)); if (strcmp(str, "iso8859") == 0) { lpNewFont->lfCharSet = ANSI_CHARSET; } else { lpNewFont->lfCharSet = OEM_CHARSET; } lpNewFont->lfOutPrecision = OUT_DEFAULT_PRECIS; lpNewFont->lfClipPrecision = CLIP_DEFAULT_PRECIS; lpNewFont->lfQuality = DEFAULT_QUALITY; ParseFontParms(names[i], 11, str, sizeof(str)); switch(str[0]) { case 'p': lpNewFont->lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS; break; case 'm': case 'c': lpNewFont->lfPitchAndFamily = FIXED_PITCH | FF_MODERN; break; default: lpNewFont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; break; } dprintf_font( stddeb, "InitFontsList // lpNewFont->lfHeight=%d\n", lpNewFont->lfHeight ); dprintf_font( stddeb, "InitFontsList // lpNewFont->lfWidth=%d\n", lpNewFont->lfWidth ); dprintf_font( stddeb, "InitFontsList // lfFaceName='%s'\n", lpNewFont->lfFaceName ); lpLogFontList[i] = lpNewFont; lpNewFont = (LPLOGFONT16) ((char *)lpNewFont + sizeof(LOGFONT16)+LF_FACESIZE); } lpLogFontList[i] = NULL; qsort(lpLogFontList,count,sizeof(*lpLogFontList),logfcmp); XFreeFontNames(names); } /************************************************************************* * EnumFonts [GDI.70] */ INT EnumFonts(HDC hDC, LPCSTR lpFaceName, FONTENUMPROC lpEnumFunc, LPARAM lpData) { HANDLE hLog; HANDLE hMet; HFONT hFont; HFONT hOldFont; LPLOGFONT16 lpLogFont; LPTEXTMETRIC16 lptm; LPSTR lpOldName; char FaceName[LF_FACESIZE]; int nRet = 0; int i; dprintf_font(stddeb,"EnumFonts(%04x, %p='%s', %08lx, %08lx)\n", hDC, lpFaceName, lpFaceName, (LONG)lpEnumFunc, lpData); if (lpEnumFunc == 0) return 0; hLog = GDI_HEAP_ALLOC( sizeof(LOGFONT16) + LF_FACESIZE ); lpLogFont = (LPLOGFONT16) GDI_HEAP_LIN_ADDR(hLog); if (lpLogFont == NULL) { fprintf(stderr,"EnumFonts // can't alloc LOGFONT struct !\n"); return 0; } hMet = GDI_HEAP_ALLOC( sizeof(TEXTMETRIC16) ); lptm = (LPTEXTMETRIC16) GDI_HEAP_LIN_ADDR(hMet); if (lptm == NULL) { GDI_HEAP_FREE(hLog); fprintf(stderr, "EnumFonts // can't alloc TEXTMETRIC struct !\n"); return 0; } if (lpFaceName != NULL) { strcpy(FaceName, lpFaceName); AnsiUpper(FaceName); } lpOldName = NULL; if (lpLogFontList[0] == NULL) InitFontsList(); for(i = 0; lpLogFontList[i] != NULL; i++) { if (lpFaceName == NULL) { if (lpOldName != NULL) { if (strcmp(lpOldName,lpLogFontList[i]->lfFaceName) == 0) continue; } lpOldName = lpLogFontList[i]->lfFaceName; } else { if (strcmp(FaceName, lpLogFontList[i]->lfFaceName) != 0) continue; } dprintf_font(stddeb,"EnumFonts // enum '%s' !\n", lpLogFontList[i]->lfFaceName); dprintf_font(stddeb,"EnumFonts // %p !\n", lpLogFontList[i]); memcpy(lpLogFont, lpLogFontList[i], sizeof(LOGFONT16) + LF_FACESIZE); hFont = CreateFontIndirect16(lpLogFont); hOldFont = SelectObject(hDC, hFont); GetTextMetrics16(hDC, lptm); SelectObject(hDC, hOldFont); DeleteObject(hFont); dprintf_font(stddeb,"EnumFonts // i=%d lpLogFont=%p lptm=%p\n", i, lpLogFont, lptm); nRet = CallEnumFontsProc((FARPROC16)lpEnumFunc, GDI_HEAP_SEG_ADDR(hLog), GDI_HEAP_SEG_ADDR(hMet), 0, (LONG)lpData ); if (nRet == 0) { dprintf_font(stddeb,"EnumFonts // EnumEnd requested by application !\n"); break; } } GDI_HEAP_FREE(hMet); GDI_HEAP_FREE(hLog); return nRet; } /************************************************************************* * EnumFontFamilies [GDI.330] */ INT EnumFontFamilies(HDC hDC, LPCSTR lpszFamily, FONTENUMPROC lpEnumFunc, LPARAM lpData) { HANDLE hLog; HANDLE hMet; HFONT hFont; HFONT hOldFont; LPENUMLOGFONT16 lpEnumLogFont; LPTEXTMETRIC16 lptm; LPSTR lpOldName; char FaceName[LF_FACESIZE]; int nRet = 0; int i; dprintf_font(stddeb,"EnumFontFamilies(%04x, %p, %08lx, %08lx)\n", hDC, lpszFamily, (DWORD)lpEnumFunc, lpData); if (lpEnumFunc == 0) return 0; hLog = GDI_HEAP_ALLOC( sizeof(ENUMLOGFONT16) ); lpEnumLogFont = (LPENUMLOGFONT16) GDI_HEAP_LIN_ADDR(hLog); if (lpEnumLogFont == NULL) { fprintf(stderr,"EnumFontFamilies // can't alloc LOGFONT struct !\n"); return 0; } hMet = GDI_HEAP_ALLOC( sizeof(TEXTMETRIC16) ); lptm = (LPTEXTMETRIC16) GDI_HEAP_LIN_ADDR(hMet); if (lptm == NULL) { GDI_HEAP_FREE(hLog); fprintf(stderr,"EnumFontFamilies // can't alloc TEXTMETRIC struct !\n"); return 0; } lpOldName = NULL; if (lpszFamily != NULL) { strcpy(FaceName, lpszFamily); AnsiUpper(FaceName); } if (lpLogFontList[0] == NULL) InitFontsList(); for(i = 0; lpLogFontList[i] != NULL; i++) { if (lpszFamily == NULL) { if (lpOldName != NULL) { if (strcmp(lpOldName,lpLogFontList[i]->lfFaceName) == 0) continue; } lpOldName = lpLogFontList[i]->lfFaceName; } else { if (strcmp(FaceName, lpLogFontList[i]->lfFaceName) != 0) continue; } memcpy(lpEnumLogFont, lpLogFontList[i], sizeof(LOGFONT16)); strcpy(lpEnumLogFont->elfFullName,""); strcpy(lpEnumLogFont->elfStyle,""); hFont = CreateFontIndirect16((LPLOGFONT16)lpEnumLogFont); hOldFont = SelectObject(hDC, hFont); GetTextMetrics16(hDC, lptm); SelectObject(hDC, hOldFont); DeleteObject(hFont); dprintf_font(stddeb, "EnumFontFamilies // i=%d lpLogFont=%p lptm=%p\n", i, lpEnumLogFont, lptm); nRet = CallEnumFontFamProc( (FARPROC16)lpEnumFunc, GDI_HEAP_SEG_ADDR(hLog), GDI_HEAP_SEG_ADDR(hMet), 0, lpData ); if (nRet == 0) { dprintf_font(stddeb,"EnumFontFamilies // EnumEnd requested by application !\n"); break; } } GDI_HEAP_FREE(hMet); GDI_HEAP_FREE(hLog); return nRet; } /************************************************************************* * GetRasterizerCaps [GDI.313] */ BOOL GetRasterizerCaps(LPRASTERIZER_STATUS lprs, UINT cbNumBytes) { /* This is not much more than a dummy */ RASTERIZER_STATUS rs; rs.nSize = sizeof(rs); rs.wFlags = 0; rs.nLanguageID = 0; return True; } /************************************************************************* * GetKerningPairs [GDI.332] */ int GetKerningPairs(HDC hDC,int cPairs,LPKERNINGPAIR16 lpKerningPairs) { /* This has to be dealt with when proper font handling is in place * * At this time kerning is ignored (set to 0) */ int i; fprintf(stdnimp,"GetKerningPairs: almost empty stub!\n"); for (i = 0; i < cPairs; i++) lpKerningPairs[i].iKernAmount = 0; return 0; }