First patch of font stuff from CodeWeaver's Patch
Huw D M Davies
h.davies1 at physics.ox.ac.uk
Sat Jan 26 09:20:35 CST 2002
Huw D M Davies <hdavies at codeweavers.com>
Charles Loep <charles at 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.
-------------- next part --------------
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;
}
More information about the wine-patches
mailing list