Huw D M Davies <hdavies@codeweavers.com> Charles Loep <charles@codeweavers.com> Various fixes for gdi font handling code including: * Using TTs VDMX table to ensure that we get exactly that same size font that Windows uses. * Fixes to many members of the metrics structures. * Font cache. * Rotated text support. * Support for GGO_GRAY?_BITMAP (ready for anti-aliased text). * Support for GGO_NATIVE.
Index: dlls/gdi/freetype.c =================================================================== RCS file: /home/wine/wine/dlls/gdi/freetype.c,v retrieving revision 1.3 diff -u -r1.3 freetype.c --- dlls/gdi/freetype.c 2001/12/24 21:10:31 1.3 +++ dlls/gdi/freetype.c 2002/01/26 13:15:00 @@ -14,10 +14,12 @@ #include "winreg.h" #include "wingdi.h" #include "wine/unicode.h" +#include "wine/port.h" #include "gdi.h" #include "font.h" #include "debugtools.h" +#include <sys/stat.h> #include <string.h> #include <dirent.h> #include <stdio.h> @@ -52,6 +54,7 @@ #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H #include <freetype/internal/sfnt.h> #endif +#include <freetype/fttrigon.h> static FT_Library library = 0; @@ -60,6 +63,7 @@ char *file; BOOL Italic; BOOL Bold; + DWORD fsCsb[2]; /* codepage bitfield from FONTSIGNATURE */ struct tagFace *next; } Face; @@ -69,25 +73,90 @@ struct tagFamily *next; } Family; +typedef struct { + GLYPHMETRICS gm; + INT adv; /* These three hold to widths of the unrotated chars */ + INT lsb; + INT bbx; + BOOL init; +} GM; + struct tagGdiFont { - DWORD ref; FT_Face ft_face; + int charset; + BOOL fake_italic; + BOOL fake_bold; + INT orientation; + GM *gm; + DWORD gmsize; + HFONT hfont; + SHORT yMax; + SHORT yMin; + struct tagGdiFont *next; }; +#define INIT_GM_SIZE 128 + +static GdiFont GdiFontList = NULL; + static Family *FontList = NULL; +static WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ', + 'R','o','m','a','n','\0'}; +static WCHAR defSans[] = {'A','r','i','a','l','\0'}; +static WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'}; + +static WCHAR defSystem[] = {'A','r','i','a','l','\0'}; +static WCHAR SystemW[] = {'S','y','s','t','e','m','\0'}; +static WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ', + 'S','e','r','i','f','\0'}; +static WCHAR HelvW[] = {'H','e','l','v','\0'}; + +static WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'}; +static WCHAR BalticW[] = {'B','a','l','t','i','c','\0'}; +static WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ', + 'E','u','r','o','p','e','a','n','\0'}; +static WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'}; +static WCHAR GreekW[] = {'G','r','e','e','k','\0'}; +static WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'}; +static WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'}; +static WCHAR ThaiW[] = {'T','h','a','i','\0'}; +static WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'}; +static WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'}; +static WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'}; + +static WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */ + WesternW, /*00*/ + Central_EuropeanW, + CyrillicW, + GreekW, + TurkishW, + HebrewW, + ArabicW, + BalticW, + VietnameseW, /*08*/ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/ + ThaiW, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*23*/ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + SymbolW /*31*/ +}; + static BOOL AddFontFileToList(char *file) { FT_Face ft_face; + TT_OS2 *pOS2; WCHAR *FamilyW, *StyleW; DWORD len; Family *family = FontList; Family **insert = &FontList; Face **insertface; + FT_Error err; + int i; TRACE("Loading font file %s\n", debugstr_a(file)); - if(FT_New_Face(library, file, 0, &ft_face)) { - ERR("Unable to load font file %s\n", debugstr_a(file)); + if((err = FT_New_Face(library, file, 0, &ft_face)) != 0) { + ERR("Unable to load font file %s err = %x\n", debugstr_a(file), err); return FALSE; } @@ -137,6 +206,31 @@ (*insertface)->next = NULL; (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0; (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0; + + pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2); + if(pOS2) { + (*insertface)->fsCsb[0] = pOS2->ulCodePageRange1; + (*insertface)->fsCsb[1] = pOS2->ulCodePageRange2; + } else { + (*insertface)->fsCsb[0] = (*insertface)->fsCsb[1] = 0; + } + + if((*insertface)->fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */ + for(i = 0; i < ft_face->num_charmaps && + !(*insertface)->fsCsb[0]; i++) { + switch(ft_face->charmaps[i]->encoding) { + case ft_encoding_unicode: + (*insertface)->fsCsb[0] = 1; + break; + case ft_encoding_symbol: + (*insertface)->fsCsb[0] = 1L << 31; + break; + default: + break; + } + } + } + FT_Done_Face(ft_face); TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), @@ -164,20 +258,38 @@ struct dirent *dent; char path[MAX_PATH]; + TRACE("Loading fonts from %s\n", debugstr_a(dirname)); + dir = opendir(dirname); if(!dir) { ERR("Can't open directory %s\n", debugstr_a(dirname)); return FALSE; } while((dent = readdir(dir)) != NULL) { + struct stat statbuf; + if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) continue; + + TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname)); + sprintf(path, "%s/%s", dirname, dent->d_name); - AddFontFileToList(path); + + if(stat(path, &statbuf) == -1) + { + WARN("Can't stat %s\n", debugstr_a(path)); + continue; + } + if(S_ISDIR(statbuf.st_mode)) + ReadFontDir(path); + else + AddFontFileToList(path); } return TRUE; } + + /************************************************************* * WineEngInit * @@ -189,57 +301,59 @@ DWORD valuelen, datalen, i = 0, type, dlen, vlen; LPSTR value; LPVOID data; + char windowsdir[MAX_PATH]; + char unixname[MAX_PATH]; + TRACE("\n"); + if(FT_Init_FreeType(&library) != 0) { ERR("Can't init FreeType library\n"); return FALSE; } + /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */ + GetWindowsDirectoryA(windowsdir, sizeof(windowsdir)); + strcat(windowsdir, "\\Fonts"); + wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname)); + ReadFontDir(unixname); + + /* then look in any directories that we've specified in the config file */ if(RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\FontDirs", - &hkey) != ERROR_SUCCESS) { - TRACE("Can't open FontDirs key in config file\n"); - return FALSE; - } + &hkey) == ERROR_SUCCESS) { - RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &valuelen, - &datalen, NULL, NULL); + RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + &valuelen, &datalen, NULL, NULL); - valuelen++; /* returned value doesn't include room for '\0' */ - value = HeapAlloc(GetProcessHeap(), 0, valuelen); - data = HeapAlloc(GetProcessHeap(), 0, datalen); - - dlen = datalen; - vlen = valuelen; - while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data, - &dlen) == ERROR_SUCCESS) { - TRACE("Got %s=%s\n", value, (LPSTR)data); - ReadFontDir((LPSTR)data); - /* reset dlen and vlen */ + valuelen++; /* returned value doesn't include room for '\0' */ + value = HeapAlloc(GetProcessHeap(), 0, valuelen); + data = HeapAlloc(GetProcessHeap(), 0, datalen); + dlen = datalen; vlen = valuelen; + while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data, + &dlen) == ERROR_SUCCESS) { + TRACE("Got %s=%s\n", value, (LPSTR)data); + ReadFontDir((LPSTR)data); + /* reset dlen and vlen */ + dlen = datalen; + vlen = valuelen; + } + HeapFree(GetProcessHeap(), 0, data); + HeapFree(GetProcessHeap(), 0, value); + RegCloseKey(hkey); } - HeapFree(GetProcessHeap(), 0, data); - HeapFree(GetProcessHeap(), 0, value); - RegCloseKey(hkey); + DumpFontList(); return TRUE; } -static FT_Face OpenFontFile(char *file, LONG height) +static LONG calc_ppem_for_height(FT_Face ft_face, LONG height) { - FT_Error err; TT_OS2 *pOS2; - FT_Face ft_face; LONG ppem; - err = FT_New_Face(library, file, 0, &ft_face); - if(err) { - ERR("FT_New_Face rets %d\n", err); - return 0; - } - pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2); if(height == 0) height = 16; @@ -260,14 +374,221 @@ if(height > 0) ppem = ft_face->units_per_EM * height / - (pOS2->usWinAscent + pOS2->usWinDescent); + (pOS2->usWinAscent + pOS2->usWinDescent); else ppem = -height; + return ppem; +} + +static LONG load_VDMX(GdiFont, LONG); + +static FT_Face OpenFontFile(GdiFont font, char *file, LONG height) +{ + FT_Error err; + FT_Face ft_face; + LONG ppem; + + err = FT_New_Face(library, file, 0, &ft_face); + if(err) { + ERR("FT_New_Face rets %d\n", err); + return 0; + } + + /* set it here, as load_VDMX needs it */ + font->ft_face = ft_face; + + /* load the VDMX table if we have one */ + ppem = load_VDMX(font, height); + if(ppem == 0) + ppem = calc_ppem_for_height(ft_face, height); + FT_Set_Pixel_Sizes(ft_face, 0, ppem); + return ft_face; } +static int get_nearest_charset(Face *face, int lfcharset) +{ + CHARSETINFO csi; + TranslateCharsetInfo((DWORD*)lfcharset, &csi, TCI_SRCCHARSET); + + if(csi.fs.fsCsb[0] & face->fsCsb[0]) return lfcharset; + + if(face->fsCsb[0] & 0x1) return ANSI_CHARSET; + + if(face->fsCsb[0] & (1L << 31)) return SYMBOL_CHARSET; + + FIXME("returning DEFAULT_CHARSET face->fsCsb[0] = %08lx file = %s\n", + face->fsCsb[0], face->file); + return DEFAULT_CHARSET; +} + +static GdiFont alloc_font(void) +{ + GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret)); + ret->gmsize = INIT_GM_SIZE; + ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + ret->gmsize * sizeof(*ret->gm)); + ret->next = NULL; + return ret; +} + +static void free_font(GdiFont font) +{ + FT_Done_Face(font->ft_face); + HeapFree(GetProcessHeap(), 0, font->gm); + HeapFree(GetProcessHeap(), 0, font); +} + + +/************************************************************* + * load_VDMX + * + * load the vdmx entry for the specified height + */ + +#define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ + ( ( (FT_ULong)_x4 << 24 ) | \ + ( (FT_ULong)_x3 << 16 ) | \ + ( (FT_ULong)_x2 << 8 ) | \ + (FT_ULong)_x1 ) + +#define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X') + +typedef struct { + BYTE bCharSet; + BYTE xRatio; + BYTE yStartRatio; + BYTE yEndRatio; +} Ratios; + + +static LONG load_VDMX(GdiFont font, LONG height) +{ + BYTE hdr[6], tmp[2], group[4]; + BYTE devXRatio, devYRatio; + USHORT numRecs, numRatios; + DWORD offset = -1; + LONG ppem = 0; + int i, result; + + result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6); + + if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */ + return ppem; + + /* FIXME: need the real device aspect ratio */ + devXRatio = 1; + devYRatio = 1; + + numRecs = GET_BE_WORD(&hdr[2]); + numRatios = GET_BE_WORD(&hdr[4]); + + for(i = 0; i < numRatios; i++) { + Ratios ratio; + + offset = (3 * 2) + (i * sizeof(Ratios)); + WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios)); + offset = -1; + + TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio); + + if(ratio.bCharSet != 1) + continue; + + if((ratio.xRatio == 0 && + ratio.yStartRatio == 0 && + ratio.yEndRatio == 0) || + (devXRatio == ratio.xRatio && + devYRatio >= ratio.yStartRatio && + devYRatio <= ratio.yEndRatio)) + { + offset = (3 * 2) + (numRatios * 4) + (i * 2); + WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2); + offset = GET_BE_WORD(tmp); + break; + } + } + + if(offset < 0) { + FIXME("No suitable ratio found"); + return ppem; + } + + if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) { + USHORT recs; + BYTE startsz, endsz; + BYTE *vTable; + + recs = GET_BE_WORD(group); + startsz = group[2]; + endsz = group[3]; + + TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz); + + vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6); + result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6); + if(result == GDI_ERROR) { + FIXME("Failed to retrieve vTable\n"); + goto end; + } + + if(height > 0) { + for(i = 0; i < recs; i++) { + SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]); + SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]); + ppem = GET_BE_WORD(&vTable[i * 6]); + + if(yMax + -yMin == height) { + font->yMax = yMax; + font->yMin = yMin; + TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin); + break; + } + if(yMax + -yMin > height) { + if(--i < 0) { + ppem = 0; + goto end; /* failed */ + } + font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]); + font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]); + TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin); + break; + } + } + if(!font->yMax) { + ppem = 0; + TRACE("ppem not found for height %ld\n", height); + } + } else { + ppem = -height; + if(ppem < startsz || ppem > endsz) + goto end; + + for(i = 0; i < recs; i++) { + USHORT yPelHeight; + yPelHeight = GET_BE_WORD(&vTable[i * 6]); + + if(yPelHeight > ppem) + break; /* failed */ + + if(yPelHeight == ppem) { + font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]); + font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]); + TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin); + break; + } + } + } + end: + HeapFree(GetProcessHeap(), 0, vTable); + } + + return ppem; +} + + /************************************************************* * WineEngCreateFontInstance * @@ -282,11 +603,28 @@ FONTOBJ *font = GDI_GetObjPtr(hfont, FONT_MAGIC); LOGFONTW *plf = &font->logfont; - TRACE("%s, h=%ld, it=%d, weight=%ld\n", debugstr_w(plf->lfFaceName), - plf->lfHeight, plf->lfItalic, plf->lfWeight); + TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n", + debugstr_w(plf->lfFaceName), plf->lfHeight, plf->lfItalic, + plf->lfWeight, plf->lfPitchAndFamily, plf->lfCharSet, plf->lfOrientation, + plf->lfEscapement); + + /* check the cache first */ + for(ret = GdiFontList; ret; ret = ret->next) { + if(ret->hfont == hfont) { + GDI_ReleaseObj(hfont); + TRACE("returning cached gdiFont(%p) for hFont %x\n", ret, hfont); + return ret; + } + } + + if(!FontList) /* No fonts installed */ + { + GDI_ReleaseObj(hfont); + TRACE("No fonts installed\n"); + return NULL; + } - ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret)); - ret->ref = 1; + ret = alloc_font(); strcpyW(FaceName, plf->lfFaceName); @@ -295,9 +633,40 @@ if(!strcmpiW(family->FamilyName, FaceName)) break; } + + if(!family) { /* do other aliases here */ + if(!strcmpiW(FaceName, SystemW)) + strcpyW(FaceName, defSystem); + else if(!strcmpiW(FaceName, MSSansSerifW)) + strcpyW(FaceName, defSans); + else if(!strcmpiW(FaceName, HelvW)) + strcpyW(FaceName, defSans); + else + goto not_found; + + for(family = FontList; family; family = family->next) { + if(!strcmpiW(family->FamilyName, FaceName)) + break; + } + } } +not_found: if(!family) { + if(plf->lfPitchAndFamily & FIXED_PITCH || + plf->lfPitchAndFamily & FF_MODERN) + strcpyW(FaceName, defFixed); + else if(plf->lfPitchAndFamily & FF_ROMAN) + strcpyW(FaceName, defSerif); + else if(plf->lfPitchAndFamily & FF_SWISS) + strcpyW(FaceName, defSans); + for(family = FontList; family; family = family->next) { + if(!strcmpiW(family->FamilyName, FaceName)) + break; + } + } + + if(!family) { family = FontList; FIXME("just using first face for now\n"); } @@ -308,41 +677,74 @@ for(face = family->FirstFace; face; face = face->next) { if(!(face->Italic ^ it) && !(face->Bold ^ bd)) break; + } + if(!face) { + face = family->FirstFace; + if(it && !face->Italic) ret->fake_italic = TRUE; + if(bd && !face->Bold) ret->fake_bold = TRUE; } - if(!face) face = family->FirstFace; + ret->charset = get_nearest_charset(face, plf->lfCharSet); TRACE("Choosen %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName)); - ret->ft_face = OpenFontFile(face->file, plf->lfHeight); + ret->ft_face = OpenFontFile(ret, face->file, plf->lfHeight); + if(ret->charset == SYMBOL_CHARSET) + FT_Select_Charmap(ret->ft_face, ft_encoding_symbol); + ret->orientation = plf->lfOrientation; GDI_ReleaseObj(hfont); - TRACE("returning %p\n", ret); + + TRACE("caching: gdiFont=%p hfont=%x\n", ret, hfont); + ret->hfont = hfont; + ret->next = GdiFontList; + GdiFontList = ret; + return ret; } -/************************************************************* - * WineEngAddRefFont - * - */ -DWORD WineEngAddRefFont(GdiFont font) +static void DumpGdiFontList(void) { - return ++font->ref; + GdiFont gdiFont; + + TRACE("---------- gdiFont Cache ----------\n"); + for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) { + FONTOBJ *font = GDI_GetObjPtr(gdiFont->hfont, FONT_MAGIC); + LOGFONTW *plf = &font->logfont; + TRACE("gdiFont=%p hfont=%x (%s)\n", + gdiFont, gdiFont->hfont, debugstr_w(plf->lfFaceName)); + GDI_ReleaseObj(gdiFont->hfont); + } } /************************************************************* - * WineEngDecRefFont + * WineEngDestroyFontInstance + * + * free the gdiFont associated with this handle * */ -DWORD WineEngDecRefFont(GdiFont font) +BOOL WineEngDestroyFontInstance(HFONT handle) { - DWORD ret = --font->ref; + GdiFont gdiFont; + GdiFont gdiPrev = NULL; - if(ret == 0) { - FT_Done_Face(font->ft_face); - HeapFree(GetProcessHeap(), 0, font); + TRACE("destroying hfont=%x\n", handle); + if(TRACE_ON(font)) + DumpGdiFontList(); + + for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) { + if(gdiFont->hfont == handle) { + if(gdiPrev) + gdiPrev->next = gdiFont->next; + else + GdiFontList = gdiFont->next; + + free_font(gdiFont); + return TRUE; + } + gdiPrev = gdiFont; } - return ret; + return FALSE; } static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf, @@ -350,10 +752,9 @@ { OUTLINETEXTMETRICW *potm; UINT size; - GdiFont font = HeapAlloc(GetProcessHeap(),0,sizeof(*font)); + GdiFont font = alloc_font(); - font->ref = 1; - font->ft_face = OpenFontFile(face->file, 100); + font->ft_face = OpenFontFile(font, face->file, 100); memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW)); @@ -368,7 +769,7 @@ pntm->ntmTm.tmDescent = TM.tmDescent; pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading; pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading; - pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWeight = TM.tmAveCharWidth; + pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth; pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth; pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight; pntm->ntmTm.tmOverhang = TM.tmOverhang; @@ -384,6 +785,9 @@ pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily; pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1; pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet; + pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS; + pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS; + pelf->elfLogFont.lfQuality = DRAFT_QUALITY; pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0; if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD; @@ -404,15 +808,15 @@ (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName), LF_FACESIZE); strncpyW(pelf->elfFullName, - (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFullName), + (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName), LF_FULLFACESIZE); strncpyW(pelf->elfStyle, (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName), LF_FACESIZE); - pelf->elfScript[0] = '\0'; /* FIXME */ + pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */ HeapFree(GetProcessHeap(), 0, potm); - WineEngDecRefFont(font); + free_font(font); return; } @@ -428,32 +832,98 @@ ENUMLOGFONTEXW elf; NEWTEXTMETRICEXW ntm; DWORD type, ret = 1; + FONTSIGNATURE fs; + CHARSETINFO csi; + int i; - TRACE("facename = %s\n", debugstr_w(plf->lfFaceName)); + TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet); if(plf->lfFaceName[0]) { for(family = FontList; family; family = family->next) { if(!strcmpiW(plf->lfFaceName, family->FamilyName)) { for(face = family->FirstFace; face; face = face->next) { GetEnumStructs(face, &elf, &ntm, &type); - TRACE("enuming '%s'\n", - debugstr_w(elf.elfLogFont.lfFaceName)); - ret = proc(&elf, &ntm, type, lparam); - if(!ret) break; + for(i = 0; i < 32; i++) { + if(face->fsCsb[0] & (1L << i)) { + fs.fsCsb[0] = 1L << i; + fs.fsCsb[1] = 0; + if(!TranslateCharsetInfo(fs.fsCsb, &csi, + TCI_SRCFONTSIG)) + csi.ciCharset = DEFAULT_CHARSET; + if(i == 31) csi.ciCharset = SYMBOL_CHARSET; + if(csi.ciCharset != DEFAULT_CHARSET) { + elf.elfLogFont.lfCharSet = + ntm.ntmTm.tmCharSet = csi.ciCharset; + if(ElfScriptsW[i]) + strcpyW(elf.elfScript, ElfScriptsW[i]); + else + FIXME("Unknown elfscript for bit %d\n", i); + TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n", + debugstr_w(elf.elfLogFont.lfFaceName), + debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle), + csi.ciCharset, type, debugstr_w(elf.elfScript), + elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight, + ntm.ntmTm.ntmFlags); + ret = proc(&elf, &ntm, type, lparam); + if(!ret) goto end; + } + } + } } } } } else { for(family = FontList; family; family = family->next) { GetEnumStructs(family->FirstFace, &elf, &ntm, &type); - TRACE("enuming '%s'\n", debugstr_w(elf.elfLogFont.lfFaceName)); - ret = proc(&elf, &ntm, type, lparam); - if(!ret) break; + for(i = 0; i < 32; i++) { + if(family->FirstFace->fsCsb[0] & (1L << i)) { + fs.fsCsb[0] = 1L << i; + fs.fsCsb[1] = 0; + if(!TranslateCharsetInfo(fs.fsCsb, &csi, + TCI_SRCFONTSIG)) + csi.ciCharset = DEFAULT_CHARSET; + if(i == 31) csi.ciCharset = SYMBOL_CHARSET; + if(csi.ciCharset != DEFAULT_CHARSET) { + elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = + csi.ciCharset; + if(ElfScriptsW[i]) + strcpyW(elf.elfScript, ElfScriptsW[i]); + else + FIXME("Unknown elfscript for bit %d\n", i); + TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n", + debugstr_w(elf.elfLogFont.lfFaceName), + debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle), + csi.ciCharset, type, debugstr_w(elf.elfScript), + elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight, + ntm.ntmTm.ntmFlags); + ret = proc(&elf, &ntm, type, lparam); + if(!ret) goto end; + } + } + } } } - +end: return ret; } +static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt) +{ + pt->x.value = vec->x >> 6; + pt->x.fract = (vec->x & 0x3f) << 10; + pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12)); + pt->y.value = vec->y >> 6; + pt->y.fract = (vec->y & 0x3f) << 10; + pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12)); + return; +} + +static FT_UInt get_glyph_index(GdiFont font, UINT glyph) +{ + if(font->charset == SYMBOL_CHARSET && glyph < 0x100) + glyph = glyph + 0xf000; + return FT_Get_Char_Index(font->ft_face, glyph); +} + /************************************************************* * WineEngGetGlyphOutline * @@ -468,58 +938,252 @@ { FT_Face ft_face = font->ft_face; FT_UInt glyph_index; - DWORD width, height, pitch, needed; + DWORD width, height, pitch, needed = 0; FT_Bitmap ft_bitmap; + FT_Error err; + INT left, right, top = 0, bottom = 0; + FT_Angle angle = 0; TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm, buflen, buf, lpmat); - if(format & GGO_GLYPH_INDEX) + if(format & GGO_GLYPH_INDEX) { glyph_index = glyph; - else - glyph_index = FT_Get_Char_Index(ft_face, glyph); + format &= ~GGO_GLYPH_INDEX; + } else + glyph_index = get_glyph_index(font, glyph); + + if(glyph_index >= font->gmsize) { + font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE; + font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm, + font->gmsize * sizeof(*font->gm)); + } else { + if(format == GGO_METRICS && font->gm[glyph_index].init) { + memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm)); + return 1; /* FIXME */ + } + } + + err = FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT); + + if(err) { + FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err); + return GDI_ERROR; + } - FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT); + left = ft_face->glyph->metrics.horiBearingX & -64; + right = ((ft_face->glyph->metrics.horiBearingX + + ft_face->glyph->metrics.width) + 63) & -64; + + font->gm[glyph_index].adv = (ft_face->glyph->metrics.horiAdvance + 63) >> 6; + font->gm[glyph_index].lsb = left >> 6; + font->gm[glyph_index].bbx = (right - left) >> 6; + + if(font->orientation == 0) { + top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;; + bottom = (ft_face->glyph->metrics.horiBearingY - + ft_face->glyph->metrics.height) & -64; + lpgm->gmCellIncX = font->gm[glyph_index].adv; + lpgm->gmCellIncY = 0; + } else { + INT xc, yc; + FT_Vector vec; + angle = font->orientation / 10 << 16; + angle |= ((font->orientation % 10) * (1 << 16)) / 10; + TRACE("angle %ld\n", angle >> 16); + for(xc = 0; xc < 2; xc++) { + for(yc = 0; yc < 2; yc++) { + vec.x = ft_face->glyph->metrics.horiBearingX + + xc * ft_face->glyph->metrics.width; + vec.y = ft_face->glyph->metrics.horiBearingY - + yc * ft_face->glyph->metrics.height; + TRACE("Vec %ld,%ld\n", vec.x, vec.y); + FT_Vector_Rotate(&vec, angle); + if(xc == 0 && yc == 0) { + left = right = vec.x; + top = bottom = vec.y; + } else { + if(vec.x < left) left = vec.x; + else if(vec.x > right) right = vec.x; + if(vec.y < bottom) bottom = vec.y; + else if(vec.y > top) top = vec.y; + } + } + } + left = left & -64; + right = (right + 63) & -64; + bottom = bottom & -64; + top = (top + 63) & -64; + + TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom); + vec.x = ft_face->glyph->metrics.horiAdvance; + vec.y = 0; + FT_Vector_Rotate(&vec, angle); + lpgm->gmCellIncX = (vec.x+63) >> 6; + lpgm->gmCellIncY = -(vec.y+63) >> 6; + } + lpgm->gmBlackBoxX = (right - left) >> 6; + lpgm->gmBlackBoxY = (top - bottom) >> 6; + lpgm->gmptGlyphOrigin.x = left >> 6; + lpgm->gmptGlyphOrigin.y = top >> 6; - lpgm->gmBlackBoxX = ft_face->glyph->metrics.width >> 6; - lpgm->gmBlackBoxY = ft_face->glyph->metrics.height >> 6; - lpgm->gmptGlyphOrigin.x = ft_face->glyph->metrics.horiBearingX >> 6; - lpgm->gmptGlyphOrigin.y = ft_face->glyph->metrics.horiBearingY >> 6; - lpgm->gmCellIncX = ft_face->glyph->metrics.horiAdvance >> 6; - lpgm->gmCellIncY = 0; + memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm)); + font->gm[glyph_index].init = TRUE; if(format == GGO_METRICS) - return TRUE; + return 1; /* FIXME */ if(ft_face->glyph->format != ft_glyph_format_outline) { FIXME("loaded a bitmap\n"); return GDI_ERROR; } - if(format == GGO_BITMAP) { + switch(format) { + case GGO_BITMAP: width = lpgm->gmBlackBoxX; height = lpgm->gmBlackBoxY; pitch = (width + 31) / 32 * 4; needed = pitch * height; - if(!buf || !buflen) return needed; + if(!buf || !buflen) break; ft_bitmap.width = width; ft_bitmap.rows = height; ft_bitmap.pitch = pitch; ft_bitmap.pixel_mode = ft_pixel_mode_mono; ft_bitmap.buffer = buf; + + if(font->orientation) { + FT_Matrix matrix; + matrix.xx = matrix.yy = FT_Cos(angle); + matrix.xy = -FT_Sin(angle); + matrix.yx = -matrix.xy; + + FT_Outline_Transform(&ft_face->glyph->outline, &matrix); + } + + FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom ); + + /* Note: FreeType will only set 'black' bits for us. */ + memset(buf, 0, needed); + FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap); + break; + + case GGO_GRAY2_BITMAP: + case GGO_GRAY4_BITMAP: + case GGO_GRAY8_BITMAP: + case WINE_GGO_GRAY16_BITMAP: + { + int mult, row, col; + BYTE *start, *ptr; + + width = lpgm->gmBlackBoxX; + height = lpgm->gmBlackBoxY; + pitch = (width + 3) / 4 * 4; + needed = pitch * height; + + if(!buf || !buflen) break; + ft_bitmap.width = width; + ft_bitmap.rows = height; + ft_bitmap.pitch = pitch; + ft_bitmap.pixel_mode = ft_pixel_mode_grays; + ft_bitmap.buffer = buf; + + if(font->orientation) { + FT_Matrix matrix; + matrix.xx = matrix.yy = FT_Cos(angle); + matrix.xy = -FT_Sin(angle); + matrix.yx = -matrix.xy; + FT_Outline_Transform(&ft_face->glyph->outline, &matrix); + } - FT_Outline_Translate(&ft_face->glyph->outline, - - ft_face->glyph->metrics.horiBearingX, - - (ft_face->glyph->metrics.horiBearingY - - ft_face->glyph->metrics.height) ); + FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom ); FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap); - } else { + + if(format == GGO_GRAY2_BITMAP) + mult = 5; + else if(format == GGO_GRAY4_BITMAP) + mult = 17; + else if(format == GGO_GRAY8_BITMAP) + mult = 65; + else if(format == WINE_GGO_GRAY16_BITMAP) + break; + else { + assert(0); + break; + } + + start = buf; + for(row = 0; row < height; row++) { + ptr = start; + for(col = 0; col < width; col++, ptr++) { + *ptr = (*(unsigned int*)ptr * mult + 128) / 256; + } + start += pitch; + } + break; + } + + case GGO_NATIVE: + { + int contour, point = 0, first_pt; + FT_Outline *outline = &ft_face->glyph->outline; + TTPOLYGONHEADER *pph; + TTPOLYCURVE *ppc; + DWORD pph_start, cpfx, type; + + if(buflen == 0) buf = NULL; + + for(contour = 0; contour < outline->n_contours; contour++) { + pph_start = needed; + pph = buf + needed; + first_pt = point; + if(buf) { + pph->dwType = TT_POLYGON_TYPE; + FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart); + } + needed += sizeof(*pph); + point++; + while(point <= outline->contours[contour]) { + ppc = buf + needed; + type = (outline->tags[point] == FT_Curve_Tag_On) ? + TT_PRIM_LINE : TT_PRIM_QSPLINE; + cpfx = 0; + do { + if(buf) + FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); + cpfx++; + point++; + } while(point <= outline->contours[contour] && + outline->tags[point] == outline->tags[point-1]); + /* At the end of a contour Windows adds the start point */ + if(point > outline->contours[contour]) { + if(buf) + FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]); + cpfx++; + } else if(outline->tags[point] == FT_Curve_Tag_On) { + /* add closing pt for bezier */ + if(buf) + FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); + cpfx++; + point++; + } + if(buf) { + ppc->wType = type; + ppc->cpfx = cpfx; + } + needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX); + } + if(buf) + pph->cb = needed - pph_start; + } + break; + } + default: FIXME("Unsupported format %d\n", format); return GDI_ERROR; } - return TRUE; + return needed; } /************************************************************* @@ -532,6 +1196,8 @@ TT_OS2 *pOS2; TT_HoriHeader *pHori; FT_Fixed x_scale, y_scale; + + TRACE("font=%p, ptm=%p\n", font, ptm); x_scale = ft_face->size->metrics.x_scale; y_scale = ft_face->size->metrics.y_scale; @@ -554,12 +1220,19 @@ ft_face->ascender, ft_face->descender, ft_face->height, pHori->Ascender, pHori->Descender, pHori->Line_Gap, ft_face->bbox.yMax, ft_face->bbox.yMin); - - ptm->tmAscent = (FT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6; - ptm->tmDescent = (FT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6; + + if(font->yMax) { + ptm->tmAscent = font->yMax; + ptm->tmDescent = -font->yMin; + ptm->tmInternalLeading = (ptm->tmAscent + ptm->tmDescent) - ft_face->size->metrics.y_ppem; + } else { + ptm->tmAscent = (FT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6; + ptm->tmDescent = (FT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6; + ptm->tmInternalLeading = (FT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent + - ft_face->units_per_EM, y_scale) + 32) >> 6; + } + ptm->tmHeight = ptm->tmAscent + ptm->tmDescent; - ptm->tmInternalLeading = (FT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent - - ft_face->units_per_EM, y_scale) + 32) >> 6; /* MSDN says: el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender))) @@ -570,7 +1243,7 @@ ptm->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6; ptm->tmMaxCharWidth = (FT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6; - ptm->tmWeight = pOS2->usWeightClass; + ptm->tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass; ptm->tmOverhang = 0; ptm->tmDigitizedAspectX = 300; ptm->tmDigitizedAspectY = 300; @@ -578,7 +1251,7 @@ ptm->tmLastChar = pOS2->usLastCharIndex; ptm->tmDefaultChar = pOS2->usDefaultChar; ptm->tmBreakChar = pOS2->usBreakChar; - ptm->tmItalic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0; + ptm->tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0); ptm->tmUnderlined = 0; /* entry in OS2 table */ ptm->tmStruckOut = 0; /* entry in OS2 table */ @@ -588,8 +1261,9 @@ ptm->tmPitchAndFamily |= TMPF_VECTOR; if(FT_IS_SFNT(ft_face)) ptm->tmPitchAndFamily |= TMPF_TRUETYPE; + ptm->tmPitchAndFamily |= FF_ROMAN; - ptm->tmCharSet = ANSI_CHARSET; + ptm->tmCharSet = font->charset; return TRUE; } /************************************************************* @@ -608,6 +1282,8 @@ WCHAR spaceW[] = {' ', '\0'}; char *cp; + TRACE("font=%p\n", font); + needed = sizeof(*potm); lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0) @@ -674,11 +1350,11 @@ potm->otmsCharSlopeRun = pHori->caret_Slope_Run; potm->otmItalicAngle = 0; /* POST table */ potm->otmEMSquare = ft_face->units_per_EM; - potm->otmAscent = pOS2->sTypoAscender; - potm->otmDescent = pOS2->sTypoDescender; - potm->otmLineGap = pOS2->sTypoLineGap; - potm->otmsCapEmHeight = pOS2->sCapHeight; - potm->otmsXHeight = pOS2->sxHeight; + potm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6; + potm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6; + potm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6; + potm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6; + potm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6; potm->otmrcFontBox.left = ft_face->bbox.xMin; potm->otmrcFontBox.right = ft_face->bbox.xMax; potm->otmrcFontBox.top = ft_face->bbox.yMin; @@ -687,19 +1363,19 @@ potm->otmMacDescent = 0; potm->otmMacLineGap = 0; potm->otmusMinimumPPEM = 0; /* TT Header */ - potm->otmptSubscriptSize.x = pOS2->ySubscriptXSize; - potm->otmptSubscriptSize.y = pOS2->ySubscriptYSize; - potm->otmptSubscriptOffset.x = pOS2->ySubscriptXOffset; - potm->otmptSubscriptOffset.y = pOS2->ySubscriptYOffset; - potm->otmptSuperscriptSize.x = pOS2->ySuperscriptXSize; - potm->otmptSuperscriptSize.y = pOS2->ySuperscriptYSize; - potm->otmptSuperscriptOffset.x = pOS2->ySuperscriptXOffset; - potm->otmptSuperscriptOffset.y = pOS2->ySuperscriptYOffset; - potm->otmsStrikeoutSize = pOS2->yStrikeoutSize; - potm->otmsStrikeoutPosition = pOS2->yStrikeoutPosition; + potm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6; + potm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6; + potm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6; + potm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6; + potm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6; + potm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6; + potm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6; + potm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6; + potm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6; + potm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6; potm->otmsUnderscoreSize = 0; /* POST Header */ potm->otmsUnderscorePosition = 0; /* POST Header */ - + /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */ cp = (char*)potm + sizeof(*potm); potm->otmpFamilyName = (LPSTR)(cp - (char*)potm); @@ -739,11 +1415,14 @@ { UINT c; GLYPHMETRICS gm; + FT_UInt glyph_index; + TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer); for(c = firstChar; c <= lastChar; c++) { WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL); - buffer[c - firstChar] = gm.gmCellIncX; + glyph_index = get_glyph_index(font, c); + buffer[c - firstChar] = font->gm[glyph_index].adv; } return TRUE; } @@ -758,6 +1437,7 @@ UINT idx; GLYPHMETRICS gm; TEXTMETRICW tm; + FT_UInt glyph_index; TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count, size); @@ -769,7 +1449,8 @@ for(idx = 0; idx < count; idx++) { WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL, NULL); - size->cx += gm.gmCellIncX; + glyph_index = get_glyph_index(font, wstr[idx]); + size->cx += font->gm[glyph_index].adv; } TRACE("return %ld,%ld\n", size->cx, size->cy); return TRUE; @@ -788,6 +1469,9 @@ DWORD len; FT_Error err; + TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n", + font, table, offset, buf, cbData); + if(!FT_IS_SFNT(ft_face)) return GDI_ERROR; @@ -806,7 +1490,7 @@ err = sfnt->load_any(tt_face, table, offset, buf, &len); if(err) { - ERR("Can't find table %08lx\n", table); + TRACE("Can't find table %08lx.\n", table); return GDI_ERROR; } return len; @@ -822,15 +1506,9 @@ { return NULL; } -DWORD WineEngAddRefFont(GdiFont font) +BOOL WineEngDestroyFontInstance(HFONT hfont) { - ERR("called but we don't have FreeType\n"); - return 0; -} -DWORD WineEngDecRefFont(GdiFont font) -{ - ERR("called but we don't have FreeType\n"); - return 0; + return FALSE; } DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam) Index: include/font.h =================================================================== RCS file: /home/wine/wine/include/font.h,v retrieving revision 1.8 diff -u -r1.8 font.h --- include/font.h 2001/10/23 20:06:33 1.8 +++ include/font.h 2002/01/26 13:15:01 @@ -73,9 +73,8 @@ extern LPWSTR FONT_mbtowc(HDC, LPCSTR, INT, INT*, UINT*); -extern DWORD WineEngAddRefFont(GdiFont); extern GdiFont WineEngCreateFontInstance(HFONT); -extern DWORD WineEngDecRefFont(GdiFont); +extern BOOL WineEngDestroyFontInstance(HFONT handle); extern DWORD WineEngEnumFonts(LPLOGFONTW, DEVICEFONTENUMPROC, LPARAM); extern BOOL WineEngGetCharWidth(GdiFont, UINT, UINT, LPINT); extern DWORD WineEngGetFontData(GdiFont, DWORD, DWORD, LPVOID, DWORD); Index: include/gdi.h =================================================================== RCS file: /home/wine/wine/include/gdi.h,v retrieving revision 1.55 diff -u -r1.55 gdi.h --- include/gdi.h 2002/01/04 18:27:45 1.55 +++ include/gdi.h 2002/01/26 13:15:01 @@ -521,4 +521,6 @@ /* objects/enhmetafile.c */ extern HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, BOOL on_disk ); +#define WINE_GGO_GRAY16_BITMAP 0x7f + #endif /* __WINE_GDI_H */ Index: objects/dc.c =================================================================== RCS file: /home/wine/wine/objects/dc.c,v retrieving revision 1.67 diff -u -r1.67 dc.c --- objects/dc.c 2001/12/17 20:58:08 1.67 +++ objects/dc.c 2002/01/26 13:15:01 @@ -316,7 +316,6 @@ newdc->hClipRgn = 0; if(dc->gdiFont) { - WineEngAddRefFont(dc->gdiFont); newdc->gdiFont = dc->gdiFont; } else newdc->gdiFont = 0; @@ -775,7 +774,6 @@ if (dc->hClipRgn) DeleteObject( dc->hClipRgn ); if (dc->hVisRgn) DeleteObject( dc->hVisRgn ); if (dc->hGCClipRgn) DeleteObject( dc->hGCClipRgn ); - if (dc->gdiFont) WineEngDecRefFont( dc->gdiFont ); PATH_DestroyGdiPath(&dc->path); GDI_FreeObject( hdc, dc ); Index: objects/font.c =================================================================== RCS file: /home/wine/wine/objects/font.c,v retrieving revision 1.61 diff -u -r1.61 font.c --- objects/font.c 2002/01/07 21:16:48 1.61 +++ objects/font.c 2002/01/26 13:15:02 @@ -1648,7 +1648,33 @@ BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar, LPABC abc ) { - return GetCharABCWidthsW( hdc, firstChar, lastChar, abc ); + INT i, wlen, count = (INT)(lastChar - firstChar + 1); + LPSTR str; + LPWSTR wstr; + BOOL ret = TRUE; + + if(count <= 0) return FALSE; + + str = HeapAlloc(GetProcessHeap(), 0, count); + for(i = 0; i < count; i++) + str[i] = (BYTE)(firstChar + i); + + wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL); + + for(i = 0; i < wlen; i++) + { + if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc)) + { + ret = FALSE; + break; + } + abc++; + } + + HeapFree(GetProcessHeap(), 0, str); + HeapFree(GetProcessHeap(), 0, wstr); + + return ret; } @@ -1671,20 +1697,22 @@ BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar, LPABC abc ) { + DC *dc = DC_GetDCPtr(hdc); int i; - LPINT widths = HeapAlloc(GetProcessHeap(),0,(lastChar-firstChar+1)*sizeof(INT)); - - FIXME("(%04x,%04x,%04x,%p), returns slightly bogus values.\n", hdc, firstChar, lastChar, abc); - - GetCharWidth32A(hdc,firstChar,lastChar,widths); + GLYPHMETRICS gm; + BOOL ret = FALSE; - for (i=firstChar;i<=lastChar;i++) { - abc[i-firstChar].abcA = 0; /* left distance */ - abc[i-firstChar].abcB = widths[i-firstChar];/* width */ - abc[i-firstChar].abcC = 0; /* right distance */ + if(dc->gdiFont) { + for (i=firstChar;i<=lastChar;i++) { + GetGlyphOutlineW(hdc, i, GGO_METRICS, &gm, 0, NULL, NULL); + abc[i-firstChar].abcA = gm.gmptGlyphOrigin.x; + abc[i-firstChar].abcB = gm.gmBlackBoxX; + abc[i-firstChar].abcC = gm.gmCellIncX - gm.gmptGlyphOrigin.x - gm.gmBlackBoxX; + } + ret = TRUE; } - HeapFree(GetProcessHeap(),0,widths); - return TRUE; + GDI_ReleaseObj(hdc); + return ret; } @@ -1708,8 +1736,20 @@ LPGLYPHMETRICS lpgm, DWORD cbBuffer, LPVOID lpBuffer, const MAT2 *lpmat2 ) { - return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, - lpmat2); + LPWSTR p = NULL; + DWORD ret; + UINT c; + + if(!(fuFormat & GGO_GLYPH_INDEX)) { + p = FONT_mbtowc(hdc, (char*)&uChar, 1, NULL, NULL); + c = p[0]; + } else + c = uChar; + ret = GetGlyphOutlineW(hdc, c, fuFormat, lpgm, cbBuffer, lpBuffer, + lpmat2); + if(p) + HeapFree(GetProcessHeap(), 0, p); + return ret; } /*********************************************************************** Index: objects/gdiobj.c =================================================================== RCS file: /home/wine/wine/objects/gdiobj.c,v retrieving revision 1.63 diff -u -r1.63 gdiobj.c --- objects/gdiobj.c 2002/01/07 21:16:48 1.63 +++ objects/gdiobj.c 2002/01/26 13:15:02 @@ -450,6 +450,17 @@ /*********************************************************************** + * FONT_DeleteObject + * + */ +static BOOL FONT_DeleteObject(HGDIOBJ hfont, FONTOBJ *fontobj) +{ + WineEngDestroyFontInstance( hfont ); + return GDI_FreeObject( hfont, fontobj ); +} + + +/*********************************************************************** * DeleteObject (GDI.69) * SysDeleteObject (GDI.605) */ @@ -495,7 +506,7 @@ { case PEN_MAGIC: return GDI_FreeObject( obj, header ); case BRUSH_MAGIC: return BRUSH_DeleteObject( obj, (BRUSHOBJ*)header ); - case FONT_MAGIC: return GDI_FreeObject( obj, header ); + case FONT_MAGIC: return FONT_DeleteObject( obj, (FONTOBJ*)header ); case PALETTE_MAGIC: return PALETTE_DeleteObject(obj,(PALETTEOBJ*)header); case BITMAP_MAGIC: return BITMAP_DeleteObject( obj, (BITMAPOBJ*)header); case REGION_MAGIC: return REGION_DeleteObject( obj, (RGNOBJ*)header ); @@ -752,19 +763,15 @@ { HGDIOBJ ret = FALSE; - if(dc->gdiFont) { - WineEngDecRefFont(dc->gdiFont); - dc->gdiFont = 0; + if(dc->hFont != hFont || dc->gdiFont == NULL) { + if(GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_VA_ABLE) + dc->gdiFont = WineEngCreateFontInstance(hFont); } - if(GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_VA_ABLE) - dc->gdiFont = WineEngCreateFontInstance(hFont); - if(dc->funcs->pSelectObject) ret = dc->funcs->pSelectObject(dc, hFont); if(ret && dc->gdiFont) { - WineEngDecRefFont(dc->gdiFont); dc->gdiFont = 0; }