gdi32: Move the font cache list out of freetype.c.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2020-10-21 11:01:50 +02:00
parent d7a54394d4
commit 82c140f1a6
3 changed files with 168 additions and 181 deletions

View File

@ -402,6 +402,9 @@ struct gdi_font *alloc_gdi_font(void)
{
struct gdi_font *font = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*font) );
font->refcount = 1;
font->matrix.eM11 = font->matrix.eM22 = 1.0;
if (!(font->handle = alloc_font_handle( font )))
{
HeapFree( GetProcessHeap(), 0, font );
@ -422,6 +425,100 @@ void free_gdi_font( struct gdi_font *font )
HeapFree( GetProcessHeap(), 0, font );
}
/* font cache */
static struct list gdi_font_list = LIST_INIT( gdi_font_list );
static struct list unused_gdi_font_list = LIST_INIT( unused_gdi_font_list );
static unsigned int unused_font_count;
#define UNUSED_CACHE_SIZE 10
static BOOL fontcmp( const struct gdi_font *font, DWORD hash, const LOGFONTW *lf,
const FMAT2 *matrix, BOOL can_use_bitmap )
{
if (font->hash != hash) return TRUE;
if (memcmp( &font->matrix, matrix, sizeof(*matrix))) return TRUE;
if (memcmp( &font->lf, lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
if (!font->can_use_bitmap != !can_use_bitmap) return TRUE;
return strcmpiW( font->lf.lfFaceName, lf->lfFaceName);
}
static DWORD hash_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
{
DWORD hash = 0, *ptr, two_chars;
WORD *pwc;
unsigned int i;
for (i = 0, ptr = (DWORD *)matrix; i < sizeof(*matrix) / sizeof(DWORD); i++, ptr++)
hash ^= *ptr;
for(i = 0, ptr = (DWORD *)lf; i < 7; i++, ptr++)
hash ^= *ptr;
for(i = 0, ptr = (DWORD *)lf->lfFaceName; i < LF_FACESIZE/2; i++, ptr++)
{
two_chars = *ptr;
pwc = (WCHAR *)&two_chars;
if(!*pwc) break;
*pwc = toupperW(*pwc);
pwc++;
*pwc = toupperW(*pwc);
hash ^= two_chars;
if(!*pwc) break;
}
hash ^= !can_use_bitmap;
return hash;
}
void cache_gdi_font( struct gdi_font *font )
{
static DWORD cache_num = 1;
font->cache_num = cache_num++;
font->hash = hash_font( &font->lf, &font->matrix, font->can_use_bitmap );
list_add_head( &gdi_font_list, &font->entry );
TRACE( "font %p\n", font );
}
struct gdi_font *find_cached_gdi_font( const LOGFONTW *lf, const FMAT2 *matrix, BOOL can_use_bitmap )
{
struct gdi_font *font;
DWORD hash = hash_font( lf, matrix, can_use_bitmap );
/* try the in-use list */
LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct gdi_font, entry )
{
if (fontcmp( font, hash, lf, matrix, can_use_bitmap )) continue;
list_remove( &font->entry );
list_add_head( &gdi_font_list, &font->entry );
if (!font->refcount++)
{
list_remove( &font->unused_entry );
unused_font_count--;
}
return font;
}
return NULL;
}
static void release_gdi_font( struct gdi_font *font )
{
if (!font) return;
if (--font->refcount) return;
TRACE( "font %p\n", font );
/* add it to the unused list */
list_add_head( &unused_gdi_font_list, &font->unused_entry );
if (unused_font_count > UNUSED_CACHE_SIZE)
{
font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct gdi_font, unused_entry );
TRACE( "freeing %p\n", font );
list_remove( &font->entry );
list_remove( &font->unused_entry );
free_gdi_font( font );
return;
}
unused_font_count++;
}
static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
{
const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
@ -687,7 +784,7 @@ static BOOL CDECL font_DeleteDC( PHYSDEV dev )
{
struct font_physdev *physdev = get_font_dev( dev );
font_funcs->pSelectFont( physdev->font, NULL, 0, NULL, 0 );
release_gdi_font( physdev->font );
HeapFree( GetProcessHeap(), 0, physdev );
return TRUE;
}
@ -982,6 +1079,7 @@ static HFONT CDECL font_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
{
UINT default_aa_flags = *aa_flags;
struct font_physdev *physdev = get_font_dev( dev );
struct gdi_font *prev = physdev->font;
DC *dc = get_physdev_dc( dev );
if (!default_aa_flags)
@ -989,7 +1087,12 @@ static HFONT CDECL font_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
next->funcs->pSelectFont( next, hfont, &default_aa_flags );
}
physdev->font = font_funcs->pSelectFont( physdev->font, dc, hfont, aa_flags, default_aa_flags );
if (!hfont) /* notification that the font has been changed by another driver */
physdev->font = NULL;
else
physdev->font = font_funcs->pSelectFont( dc, hfont, aa_flags, default_aa_flags );
if (prev) release_gdi_font( prev );
return physdev->font ? hfont : 0;
}

View File

@ -310,18 +310,6 @@ typedef struct {
BOOL init;
} GM;
typedef struct {
FLOAT eM11, eM12;
FLOAT eM21, eM22;
} FMAT2;
typedef struct {
DWORD hash;
LOGFONTW lf;
FMAT2 matrix;
BOOL can_use_bitmap;
} FONT_DESC;
typedef struct tagGdiFont GdiFont;
typedef struct {
@ -332,9 +320,6 @@ typedef struct {
struct tagGdiFont {
struct gdi_font *gdi_font;
struct list entry;
struct list unused_entry;
unsigned int refcount;
GM **gm;
DWORD gmsize;
OUTLINETEXTMETRICW *potm;
@ -353,7 +338,6 @@ struct tagGdiFont {
BYTE underline;
BYTE strikeout;
INT orientation;
FONT_DESC font_desc;
LONG aveWidth, ppem;
double scale_y;
SHORT yMax;
@ -366,7 +350,6 @@ struct tagGdiFont {
VOID *GSUB_Table;
const VOID *vert_feature;
ULONG ttc_item_offset; /* 0 if font is not a part of TrueType collection */
DWORD cache_num;
struct font_fileinfo *fileinfo;
};
@ -393,10 +376,6 @@ struct enum_charset_list {
#define GM_BLOCK_SIZE 128
#define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
static struct list gdi_font_list = LIST_INIT(gdi_font_list);
static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
static unsigned int unused_font_count;
#define UNUSED_CACHE_SIZE 10
static struct list system_links = LIST_INIT(system_links);
static struct list font_subst_list = LIST_INIT(font_subst_list);
@ -4103,12 +4082,10 @@ static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
static BOOL CDECL freetype_alloc_font( struct gdi_font *font )
{
GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
ret->refcount = 1;
ret->gmsize = 1;
ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
ret->potm = NULL;
ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
ret->total_kern_pairs = (DWORD)-1;
ret->kern_pairs = NULL;
list_init(&ret->child_fonts);
@ -4401,116 +4378,6 @@ static LONG load_VDMX(GdiFont *font, LONG height)
return ppem;
}
static void dump_gdi_font_list(void)
{
GdiFont *font;
TRACE("---------- Font Cache ----------\n");
LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
}
static void grab_font( GdiFont *font )
{
if (!font->refcount++)
{
list_remove( &font->unused_entry );
unused_font_count--;
}
}
static void release_font( struct gdi_font *gdi_font )
{
GdiFont *font;
if (!gdi_font) return;
if (!(font = get_font_ptr(gdi_font))) return;
if (!--font->refcount)
{
TRACE( "font %p\n", font );
/* add it to the unused list */
list_add_head( &unused_gdi_font_list, &font->unused_entry );
if (unused_font_count > UNUSED_CACHE_SIZE)
{
font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
TRACE( "freeing %p\n", font );
list_remove( &font->entry );
list_remove( &font->unused_entry );
free_gdi_font( font->gdi_font );
}
else unused_font_count++;
if (TRACE_ON(font)) dump_gdi_font_list();
}
}
static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
{
if(font->font_desc.hash != fd->hash) return TRUE;
if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
}
static void calc_hash(FONT_DESC *pfd)
{
DWORD hash = 0, *ptr, two_chars;
WORD *pwc;
unsigned int i;
for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
hash ^= *ptr;
for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
hash ^= *ptr;
for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
two_chars = *ptr;
pwc = (WCHAR *)&two_chars;
if(!*pwc) break;
*pwc = toupperW(*pwc);
pwc++;
*pwc = toupperW(*pwc);
hash ^= two_chars;
if(!*pwc) break;
}
hash ^= !pfd->can_use_bitmap;
pfd->hash = hash;
}
static GdiFont *find_in_cache(const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
{
GdiFont *ret;
FONT_DESC fd;
fd.lf = *plf;
fd.matrix = *pmat;
fd.can_use_bitmap = can_use_bitmap;
calc_hash(&fd);
/* try the in-use list */
LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
{
if(fontcmp(ret, &fd)) continue;
if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
list_remove( &ret->entry );
list_add_head( &gdi_font_list, &ret->entry );
grab_font( ret );
return ret;
}
return NULL;
}
static void add_to_cache(GdiFont *font)
{
static DWORD cache_num = 1;
font->cache_num = cache_num++;
list_add_head(&gdi_font_list, &font->entry);
TRACE( "font %p\n", font );
}
/*************************************************************
* create_child_font_list
*/
@ -4927,9 +4794,10 @@ static void fill_fileinfo_from_face( GdiFont *font, Face *face )
/*************************************************************
* freetype_SelectFont
*/
static struct gdi_font * CDECL freetype_SelectFont( struct gdi_font *prev, DC *dc, HFONT hfont,
UINT *aa_flags, UINT default_aa_flags )
static struct gdi_font * CDECL freetype_SelectFont( DC *dc, HFONT hfont, UINT *aa_flags,
UINT default_aa_flags )
{
struct gdi_font *gdi_font;
GdiFont *ret;
Face *face, *best, *best_bitmap;
Family *family, *last_resort_family;
@ -4944,12 +4812,6 @@ static struct gdi_font * CDECL freetype_SelectFont( struct gdi_font *prev, DC *d
FontSubst *psub = NULL;
const SYSTEM_LINKS *font_link;
if (!hfont) /* notification that the font has been changed by another driver */
{
release_font( prev );
return NULL;
}
GetObjectW( hfont, sizeof(lf), &lf );
lf.lfWidth = abs(lf.lfWidth);
@ -4993,18 +4855,19 @@ static struct gdi_font * CDECL freetype_SelectFont( struct gdi_font *prev, DC *d
EnterCriticalSection( &freetype_cs );
/* check the cache first */
if((ret = find_in_cache(&lf, &dcmat, can_use_bitmap)) != NULL) {
if ((gdi_font = find_cached_gdi_font( &lf, &dcmat, can_use_bitmap ))) {
ret = get_font_ptr( gdi_font );
TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
goto done;
}
TRACE("not in cache\n");
ret = get_font_ptr( alloc_gdi_font() );
gdi_font = alloc_gdi_font();
ret = get_font_ptr( gdi_font );
ret->font_desc.matrix = dcmat;
ret->font_desc.lf = lf;
ret->font_desc.can_use_bitmap = can_use_bitmap;
calc_hash(&ret->font_desc);
gdi_font->matrix = dcmat;
gdi_font->lf = lf;
gdi_font->can_use_bitmap = can_use_bitmap;
/* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
SYMBOL_CHARSET so that Symbol gets picked irrespective of the
@ -5196,7 +5059,7 @@ static struct gdi_font * CDECL freetype_SelectFont( struct gdi_font *prev, DC *d
}
if(!last_resort_family) {
FIXME("can't find a single appropriate font - bailing\n");
free_gdi_font(ret->gdi_font);
free_gdi_font(gdi_font);
ret = NULL;
goto done;
}
@ -5275,23 +5138,23 @@ found_face:
if(!face->scalable) {
/* Windows uses integer scaling factors for bitmap fonts */
INT scale, scaled_height;
GdiFont *cachedfont;
struct gdi_font *cachedfont;
/* FIXME: rotation of bitmap fonts is ignored */
height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
height = abs(GDI_ROUND( (double)height * gdi_font->matrix.eM22 ));
if (ret->aveWidth)
ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
ret->aveWidth = (double)ret->aveWidth * gdi_font->matrix.eM11;
gdi_font->matrix.eM11 = gdi_font->matrix.eM22 = 1.0;
dcmat.eM11 = dcmat.eM22 = 1.0;
/* As we changed the matrix, we need to search the cache for the font again,
* otherwise we might explode the cache. */
if((cachedfont = find_in_cache(&lf, &dcmat, can_use_bitmap)) != NULL) {
if((cachedfont = find_cached_gdi_font( &lf, &dcmat, can_use_bitmap ))) {
TRACE("Found cached font after non-scalable matrix rescale!\n");
free_gdi_font( ret->gdi_font );
ret = cachedfont;
free_gdi_font( gdi_font );
gdi_font = cachedfont;
ret = get_font_ptr( gdi_font );
goto done;
}
calc_hash(&ret->font_desc);
if (height != 0) height = diff;
height += face->size.height;
@ -5315,7 +5178,7 @@ found_face:
if (!ret->ft_face)
{
free_gdi_font( ret->gdi_font );
free_gdi_font( gdi_font );
ret = NULL;
goto done;
}
@ -5352,7 +5215,7 @@ found_face:
TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
add_to_cache(ret);
cache_gdi_font( gdi_font );
done:
if (ret)
{
@ -5395,10 +5258,9 @@ done:
}
}
TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
release_font( prev );
}
LeaveCriticalSection( &freetype_cs );
return ret->gdi_font;
return gdi_font;
}
static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
@ -6063,6 +5925,7 @@ enum matrices_index
static BOOL get_transform_matrices( GdiFont *font, BOOL vertical, const MAT2 *user_transform,
FT_Matrix matrices[3] )
{
struct gdi_font *gdi_font = font->gdi_font;
static const FT_Matrix identity_mat = { (1 << 16), 0, 0, (1 << 16) };
BOOL needs_transform = FALSE;
double width_ratio;
@ -6135,13 +5998,13 @@ static BOOL get_transform_matrices( GdiFont *font, BOOL vertical, const MAT2 *us
}
/* World transform */
if (!is_identity_FMAT2( &font->font_desc.matrix ))
if (!is_identity_FMAT2( &gdi_font->matrix ))
{
FT_Matrix world_mat;
world_mat.xx = FT_FixedFromFloat( font->font_desc.matrix.eM11 );
world_mat.xy = -FT_FixedFromFloat( font->font_desc.matrix.eM21 );
world_mat.yx = -FT_FixedFromFloat( font->font_desc.matrix.eM12 );
world_mat.yy = FT_FixedFromFloat( font->font_desc.matrix.eM22 );
world_mat.xx = FT_FixedFromFloat( gdi_font->matrix.eM11 );
world_mat.xy = -FT_FixedFromFloat( gdi_font->matrix.eM21 );
world_mat.yx = -FT_FixedFromFloat( gdi_font->matrix.eM12 );
world_mat.yy = FT_FixedFromFloat( gdi_font->matrix.eM22 );
for (i = 0; i < 3; i++)
pFT_Matrix_Multiply( &world_mat, &matrices[i] );
@ -6937,6 +6800,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
GLYPHMETRICS gm;
FT_Face ft_face = incoming_font->ft_face;
GdiFont *font = incoming_font;
struct gdi_font *gdi_font = font->gdi_font;
FT_Glyph_Metrics metrics;
FT_UInt glyph_index;
DWORD needed = 0;
@ -6952,8 +6816,8 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
buflen, buf, lpmat);
TRACE("font transform %f %f %f %f\n",
font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
gdi_font->matrix.eM11, gdi_font->matrix.eM12,
gdi_font->matrix.eM21, gdi_font->matrix.eM22);
if(format & GGO_GLYPH_INDEX) {
if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
@ -6971,6 +6835,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
BOOL vert;
get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
ft_face = font->ft_face;
gdi_font = font->gdi_font;
if (!vert && tategaki)
tategaki = check_unicode_tategaki(glyph);
}
@ -7186,6 +7051,7 @@ static BOOL get_bitmap_text_metrics(GdiFont *font)
static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
{
const struct gdi_font *gdi_font = font->gdi_font;
double scale_x, scale_y;
if (font->aveWidth)
@ -7196,8 +7062,8 @@ static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
else
scale_x = font->scale_y;
scale_x *= fabs(font->font_desc.matrix.eM11);
scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
scale_x *= fabs(gdi_font->matrix.eM11);
scale_y = font->scale_y * fabs(gdi_font->matrix.eM22);
#define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
#define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
@ -7225,6 +7091,7 @@ static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
{
const struct gdi_font *gdi_font = font->gdi_font;
double scale_x, scale_y;
if (font->aveWidth)
@ -7235,8 +7102,8 @@ static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *
else
scale_x = font->scale_y;
scale_x *= fabs(font->font_desc.matrix.eM11);
scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
scale_x *= fabs(gdi_font->matrix.eM11);
scale_y = font->scale_y * fabs(gdi_font->matrix.eM22);
scale_font_metrics(font, &potm->otmTextMetrics);
@ -7684,13 +7551,14 @@ static UINT CDECL freetype_GetOutlineTextMetrics( struct gdi_font *gdi_font, UIN
static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
{
struct gdi_font *gdi_font = font->gdi_font;
const struct list *face_list;
Face *child_face = NULL, *best_face = NULL;
UINT penalty = 0, new_penalty = 0;
BOOL bold, italic, bd, it;
italic = !!font->font_desc.lf.lfItalic;
bold = font->font_desc.lf.lfWeight > FW_MEDIUM;
italic = !!gdi_font->lf.lfItalic;
bold = gdi_font->lf.lfWeight > FW_MEDIUM;
face_list = get_face_list_from_family( child->face->family );
LIST_FOR_EACH_ENTRY( child_face, face_list, Face, entry )
@ -7717,7 +7585,9 @@ static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
child->font->fake_italic = italic && !( child_face->ntmFlags & NTM_ITALIC );
child->font->fake_bold = bold && !( child_face->ntmFlags & NTM_BOLD );
child->font->font_desc = font->font_desc;
child->font->gdi_font->lf = gdi_font->lf;
child->font->gdi_font->matrix = gdi_font->matrix;
child->font->gdi_font->can_use_bitmap = gdi_font->can_use_bitmap;
child->font->ntmFlags = child_face->ntmFlags;
child->font->orientation = font->orientation;
child->font->scale_y = font->scale_y;
@ -8059,7 +7929,7 @@ static BOOL CDECL freetype_GetFontRealizationInfo( struct gdi_font *gdi_font, st
if(FT_IS_SCALABLE(font->ft_face))
info->flags |= 2;
info->cache_num = font->cache_num;
info->cache_num = gdi_font->cache_num;
info->instance_id = gdi_font->handle;
if (info->size == sizeof(*info))
{

View File

@ -309,10 +309,21 @@ struct font_fileinfo
WCHAR path[1];
};
typedef struct { FLOAT eM11, eM12, eM21, eM22; } FMAT2;
struct gdi_font
{
void *private; /* font backend private data */
DWORD handle;
struct list entry;
struct list unused_entry;
DWORD refcount;
/* the following members can be accessed without locking, they are never modified after creation */
void *private; /* font backend private data */
DWORD handle;
DWORD cache_num;
DWORD hash;
LOGFONTW lf;
FMAT2 matrix;
BOOL can_use_bitmap;
};
struct font_backend_funcs
@ -336,8 +347,8 @@ struct font_backend_funcs
BOOL (CDECL *pGetTextExtentExPointI)( struct gdi_font *font, const WORD *indices, INT count, INT *dxs );
INT (CDECL *pGetTextFace)( struct gdi_font *font, INT count, WCHAR *str );
BOOL (CDECL *pGetTextMetrics)( struct gdi_font *font, TEXTMETRICW *metrics );
struct gdi_font * (CDECL *pSelectFont)( struct gdi_font *prev, DC *dc, HFONT hfont,
UINT *aa_flags, UINT default_aa_flags );
struct gdi_font * (CDECL *pSelectFont)( DC *dc, HFONT hfont, UINT *aa_flags, UINT default_aa_flags );
INT (CDECL *pAddFontResourceEx)( LPCWSTR file, DWORD flags, PVOID pdv );
INT (CDECL *pRemoveFontResourceEx)( LPCWSTR file, DWORD flags, PVOID pdv );
HANDLE (CDECL *pAddFontMemResourceEx)( void *font, DWORD size, PVOID pdv, DWORD *count );
@ -354,6 +365,9 @@ struct font_backend_funcs
extern struct gdi_font *alloc_gdi_font(void) DECLSPEC_HIDDEN;
extern void free_gdi_font( struct gdi_font *font ) DECLSPEC_HIDDEN;
extern void cache_gdi_font( struct gdi_font *font ) DECLSPEC_HIDDEN;
extern struct gdi_font *find_cached_gdi_font( const LOGFONTW *lf, const FMAT2 *matrix,
BOOL can_use_bitmap ) DECLSPEC_HIDDEN;
extern void font_init(void) DECLSPEC_HIDDEN;
/* freetype.c */