Commit eef8a44d authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

dwrite: Move glyph advances cache to PE side.

parent b167df37
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/list.h" #include "wine/list.h"
#include "wine/rbtree.h"
#define MS_GSUB_TAG DWRITE_MAKE_OPENTYPE_TAG('G','S','U','B') #define MS_GSUB_TAG DWRITE_MAKE_OPENTYPE_TAG('G','S','U','B')
#define MS_GPOS_TAG DWRITE_MAKE_OPENTYPE_TAG('G','P','O','S') #define MS_GPOS_TAG DWRITE_MAKE_OPENTYPE_TAG('G','P','O','S')
...@@ -240,6 +241,13 @@ struct dwrite_fontface ...@@ -240,6 +241,13 @@ struct dwrite_fontface
font_object_handle font_object; font_object_handle font_object;
void *data_context; void *data_context;
p_dwrite_fontface_get_font_object get_font_object; p_dwrite_fontface_get_font_object get_font_object;
struct
{
struct wine_rb_tree tree;
struct list mru;
size_t max_size;
size_t size;
} cache;
CRITICAL_SECTION cs; CRITICAL_SECTION cs;
USHORT simulations; USHORT simulations;
...@@ -725,8 +733,8 @@ struct font_backend_funcs ...@@ -725,8 +733,8 @@ struct font_backend_funcs
int (CDECL *get_glyph_outline)(font_object_handle object, float emsize, unsigned int simulations, UINT16 glyph, int (CDECL *get_glyph_outline)(font_object_handle object, float emsize, unsigned int simulations, UINT16 glyph,
struct dwrite_outline *outline); struct dwrite_outline *outline);
UINT16 (CDECL *get_glyph_count)(font_object_handle object); UINT16 (CDECL *get_glyph_count)(font_object_handle object);
INT32 (CDECL *get_glyph_advance)(void *key, float em_size, UINT16 index, DWRITE_MEASURING_MODE measuring_mode, INT32 (CDECL *get_glyph_advance)(font_object_handle object, float em_size, UINT16 glyph,
BOOL *has_contours); DWRITE_MEASURING_MODE measuring_mode, BOOL *has_contours);
void (CDECL *get_glyph_bbox)(struct dwrite_glyphbitmap *bitmap_desc); void (CDECL *get_glyph_bbox)(struct dwrite_glyphbitmap *bitmap_desc);
BOOL (CDECL *get_glyph_bitmap)(struct dwrite_glyphbitmap *bitmap_desc); BOOL (CDECL *get_glyph_bitmap)(struct dwrite_glyphbitmap *bitmap_desc);
void (CDECL *get_design_glyph_metrics)(font_object_handle object, UINT16 upem, UINT16 ascent, unsigned int simulations, void (CDECL *get_design_glyph_metrics)(font_object_handle object, UINT16 upem, UINT16 ascent, unsigned int simulations,
......
...@@ -52,6 +52,111 @@ void dwrite_fontface_get_glyph_bbox(struct dwrite_glyphbitmap *bitmap) ...@@ -52,6 +52,111 @@ void dwrite_fontface_get_glyph_bbox(struct dwrite_glyphbitmap *bitmap)
font_funcs->get_glyph_bbox(bitmap); font_funcs->get_glyph_bbox(bitmap);
} }
struct cache_key
{
float size;
unsigned short glyph;
unsigned short mode;
};
struct cache_entry
{
struct wine_rb_entry entry;
struct list mru;
struct cache_key key;
float advance;
unsigned int has_contours : 1;
};
static struct cache_entry * fontface_get_cache_entry(struct dwrite_fontface *fontface, const struct cache_key *key)
{
struct cache_entry *entry;
struct wine_rb_entry *e;
if (!(e = wine_rb_get(&fontface->cache.tree, key))) return NULL;
entry = WINE_RB_ENTRY_VALUE(e, struct cache_entry, entry);
list_remove(&entry->mru);
list_add_head(&fontface->cache.mru, &entry->mru);
return WINE_RB_ENTRY_VALUE(entry, struct cache_entry, entry);
}
static size_t fontface_get_cache_entry_size(const struct cache_entry *entry)
{
return sizeof(*entry);
}
static float fontface_get_glyph_advance(struct dwrite_fontface *fontface, float fontsize, unsigned short glyph,
unsigned short mode, BOOL *has_contours)
{
struct cache_key key = { .size = fontsize, .glyph = glyph, .mode = mode };
struct cache_entry *entry, *old_entry;
size_t size;
BOOL value;
if (!(entry = fontface_get_cache_entry(fontface, &key)))
{
if (!(entry = calloc(1, sizeof(*entry))))
return 0.0f;
entry->advance = font_funcs->get_glyph_advance(fontface->get_font_object(fontface), fontsize, glyph, mode, &value);
entry->has_contours = !!value;
entry->key = key;
size = fontface_get_cache_entry_size(entry);
if ((fontface->cache.size + size > fontface->cache.max_size) && !list_empty(&fontface->cache.mru))
{
old_entry = LIST_ENTRY(list_tail(&fontface->cache.mru), struct cache_entry, mru);
fontface->cache.size -= fontface_get_cache_entry_size(old_entry);
wine_rb_remove(&fontface->cache.tree, &old_entry->entry);
list_remove(&old_entry->mru);
free(old_entry);
}
list_add_head(&fontface->cache.mru, &entry->mru);
if (wine_rb_put(&fontface->cache.tree, &key, &entry->entry) == -1)
{
WARN("Failed to add cache entry.\n");
return 0.0f;
}
fontface->cache.size += size;
}
*has_contours = entry->has_contours;
return entry->advance;
}
static int fontface_cache_compare(const void *k, const struct wine_rb_entry *e)
{
const struct cache_entry *entry = WINE_RB_ENTRY_VALUE(e, const struct cache_entry, entry);
const struct cache_key *key = k, *key2 = &entry->key;
if (key->size != key2->size) return key->size < key2->size ? -1 : 1;
if (key->glyph != key2->glyph) return (int)key->glyph - (int)key2->glyph;
if (key->mode != key2->mode) return (int)key->mode - (int)key2->mode;
return 0;
}
static void fontface_cache_init(struct dwrite_fontface *fontface)
{
wine_rb_init(&fontface->cache.tree, fontface_cache_compare);
list_init(&fontface->cache.mru);
fontface->cache.max_size = 0x8000;
}
static void fontface_cache_clear(struct dwrite_fontface *fontface)
{
struct cache_entry *entry, *entry2;
LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &fontface->cache.mru, struct cache_entry, mru)
{
list_remove(&entry->mru);
free(entry);
}
memset(&fontface->cache, 0, sizeof(fontface->cache));
}
struct dwrite_font_propvec { struct dwrite_font_propvec {
FLOAT stretch; FLOAT stretch;
FLOAT style; FLOAT style;
...@@ -656,6 +761,7 @@ static ULONG WINAPI dwritefontface_Release(IDWriteFontFace5 *iface) ...@@ -656,6 +761,7 @@ static ULONG WINAPI dwritefontface_Release(IDWriteFontFace5 *iface)
IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, fontface->data_context); IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, fontface->data_context);
IDWriteFontFileStream_Release(fontface->stream); IDWriteFontFileStream_Release(fontface->stream);
} }
fontface_cache_clear(fontface);
dwrite_cmap_release(&fontface->cmap); dwrite_cmap_release(&fontface->cmap);
IDWriteFactory7_Release(fontface->factory); IDWriteFactory7_Release(fontface->factory);
...@@ -1019,7 +1125,7 @@ static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFac ...@@ -1019,7 +1125,7 @@ static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFac
UINT32 adjustment = fontface_get_horz_metric_adjustment(fontface); UINT32 adjustment = fontface_get_horz_metric_adjustment(fontface);
DWRITE_MEASURING_MODE mode; DWRITE_MEASURING_MODE mode;
FLOAT scale, size; FLOAT scale, size;
HRESULT hr; HRESULT hr = S_OK;
UINT32 i; UINT32 i;
TRACE("%p, %.8e, %.8e, %p, %d, %p, %u, %p, %d.\n", iface, emSize, ppdip, m, use_gdi_natural, glyphs, TRACE("%p, %.8e, %.8e, %p, %d, %p, %u, %p, %d.\n", iface, emSize, ppdip, m, use_gdi_natural, glyphs,
...@@ -1032,16 +1138,18 @@ static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFac ...@@ -1032,16 +1138,18 @@ static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFac
scale = size / fontface->metrics.designUnitsPerEm; scale = size / fontface->metrics.designUnitsPerEm;
mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC; mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
for (i = 0; i < glyph_count; i++) { EnterCriticalSection(&fontface->cs);
for (i = 0; i < glyph_count; ++i)
{
DWRITE_GLYPH_METRICS *ret = metrics + i; DWRITE_GLYPH_METRICS *ret = metrics + i;
DWRITE_GLYPH_METRICS design; DWRITE_GLYPH_METRICS design;
BOOL has_contours; BOOL has_contours;
hr = IDWriteFontFace5_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways); hr = IDWriteFontFace5_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
if (FAILED(hr)) if (FAILED(hr))
return hr; break;
ret->advanceWidth = font_funcs->get_glyph_advance(iface, size, glyphs[i], mode, &has_contours); ret->advanceWidth = fontface_get_glyph_advance(fontface, size, glyphs[i], mode, &has_contours);
if (has_contours) if (has_contours)
ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size + adjustment); ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size + adjustment);
else else
...@@ -1056,6 +1164,7 @@ static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFac ...@@ -1056,6 +1164,7 @@ static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFac
SCALE_METRIC(verticalOriginY); SCALE_METRIC(verticalOriginY);
#undef SCALE_METRIC #undef SCALE_METRIC
} }
LeaveCriticalSection(&fontface->cs);
return S_OK; return S_OK;
} }
...@@ -1172,8 +1281,8 @@ static int fontface_get_design_advance(struct dwrite_fontface *fontface, DWRITE_ ...@@ -1172,8 +1281,8 @@ static int fontface_get_design_advance(struct dwrite_fontface *fontface, DWRITE_
switch (measuring_mode) switch (measuring_mode)
{ {
case DWRITE_MEASURING_MODE_NATURAL: case DWRITE_MEASURING_MODE_NATURAL:
advance = font_funcs->get_glyph_advance(&fontface->IDWriteFontFace5_iface, fontface->metrics.designUnitsPerEm, advance = fontface_get_glyph_advance(fontface, fontface->metrics.designUnitsPerEm, glyph,
glyph, measuring_mode, &has_contours); measuring_mode, &has_contours);
if (has_contours) if (has_contours)
advance += adjustment; advance += adjustment;
...@@ -1187,8 +1296,7 @@ static int fontface_get_design_advance(struct dwrite_fontface *fontface, DWRITE_ ...@@ -1187,8 +1296,7 @@ static int fontface_get_design_advance(struct dwrite_fontface *fontface, DWRITE_
if (transform && memcmp(transform, &identity, sizeof(*transform))) if (transform && memcmp(transform, &identity, sizeof(*transform)))
FIXME("Transform is not supported.\n"); FIXME("Transform is not supported.\n");
advance = font_funcs->get_glyph_advance(&fontface->IDWriteFontFace5_iface, emsize, glyph, measuring_mode, advance = fontface_get_glyph_advance(fontface, emsize, glyph, measuring_mode, &has_contours);
&has_contours);
if (has_contours) if (has_contours)
advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize + adjustment); advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize + adjustment);
else else
...@@ -1212,11 +1320,13 @@ static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace5 *i ...@@ -1212,11 +1320,13 @@ static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace5 *i
if (is_sideways) if (is_sideways)
FIXME("sideways mode not supported\n"); FIXME("sideways mode not supported\n");
EnterCriticalSection(&fontface->cs);
for (i = 0; i < glyph_count; ++i) for (i = 0; i < glyph_count; ++i)
{ {
advances[i] = fontface_get_design_advance(fontface, DWRITE_MEASURING_MODE_NATURAL, advances[i] = fontface_get_design_advance(fontface, DWRITE_MEASURING_MODE_NATURAL,
fontface->metrics.designUnitsPerEm, 1.0f, NULL, glyphs[i], is_sideways); fontface->metrics.designUnitsPerEm, 1.0f, NULL, glyphs[i], is_sideways);
} }
LeaveCriticalSection(&fontface->cs);
return S_OK; return S_OK;
} }
...@@ -1243,11 +1353,14 @@ static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontF ...@@ -1243,11 +1353,14 @@ static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontF
} }
measuring_mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC; measuring_mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
EnterCriticalSection(&fontface->cs);
for (i = 0; i < glyph_count; ++i) for (i = 0; i < glyph_count; ++i)
{ {
advances[i] = fontface_get_design_advance(fontface, measuring_mode, em_size, ppdip, transform, advances[i] = fontface_get_design_advance(fontface, measuring_mode, em_size, ppdip, transform,
glyphs[i], is_sideways); glyphs[i], is_sideways);
} }
LeaveCriticalSection(&fontface->cs);
return S_OK; return S_OK;
} }
...@@ -5101,6 +5214,7 @@ HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_li ...@@ -5101,6 +5214,7 @@ HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_li
fontface->stream = desc->stream; fontface->stream = desc->stream;
IDWriteFontFileStream_AddRef(fontface->stream); IDWriteFontFileStream_AddRef(fontface->stream);
InitializeCriticalSection(&fontface->cs); InitializeCriticalSection(&fontface->cs);
fontface_cache_init(fontface);
stream_desc.stream = fontface->stream; stream_desc.stream = fontface->stream;
stream_desc.face_type = desc->face_type; stream_desc.face_type = desc->face_type;
...@@ -6027,7 +6141,9 @@ float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRIT ...@@ -6027,7 +6141,9 @@ float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRIT
if (is_sideways) if (is_sideways)
FIXME("Sideways mode is not supported.\n"); FIXME("Sideways mode is not supported.\n");
EnterCriticalSection(&fontface->cs);
advance = fontface_get_design_advance(fontface, measuring_mode, emsize, ppdip, transform, glyph, is_sideways); advance = fontface_get_design_advance(fontface, measuring_mode, emsize, ppdip, transform, glyph, is_sideways);
LeaveCriticalSection(&fontface->cs);
switch (measuring_mode) switch (measuring_mode)
{ {
......
...@@ -781,30 +781,25 @@ static BOOL CDECL freetype_get_glyph_bitmap(struct dwrite_glyphbitmap *bitmap) ...@@ -781,30 +781,25 @@ static BOOL CDECL freetype_get_glyph_bitmap(struct dwrite_glyphbitmap *bitmap)
return ret; return ret;
} }
static INT32 CDECL freetype_get_glyph_advance(void *key, float emSize, UINT16 index, static INT32 CDECL freetype_get_glyph_advance(font_object_handle object, float emsize, UINT16 glyph,
DWRITE_MEASURING_MODE mode, BOOL *has_contours) DWRITE_MEASURING_MODE mode, BOOL *has_contours)
{ {
FTC_ImageTypeRec imagetype; FT_Face face = object;
FT_Glyph glyph; INT32 advance = 0;
INT32 advance; FT_Size size;
imagetype.face_id = key; *has_contours = FALSE;
imagetype.width = 0;
imagetype.height = emSize;
imagetype.flags = FT_LOAD_DEFAULT;
if (mode == DWRITE_MEASURING_MODE_NATURAL)
imagetype.flags |= FT_LOAD_NO_HINTING;
RtlEnterCriticalSection(&freetype_cs); if (!(size = freetype_set_face_size(face, emsize)))
if (pFTC_ImageCache_Lookup(image_cache, &imagetype, index, &glyph, NULL) == 0) { return 0;
*has_contours = glyph->format == FT_GLYPH_FORMAT_OUTLINE && ((FT_OutlineGlyph)glyph)->outline.n_contours;
advance = glyph->advance.x >> 16; if (!pFT_Load_Glyph(face, glyph, mode == DWRITE_MEASURING_MODE_NATURAL ? FT_LOAD_NO_HINTING : 0))
} {
else { advance = face->glyph->advance.x >> 6;
*has_contours = FALSE; *has_contours = freetype_glyph_has_contours(face);
advance = 0;
} }
RtlLeaveCriticalSection(&freetype_cs);
pFT_Done_Size(size);
return advance; return advance;
} }
...@@ -863,8 +858,8 @@ static UINT16 CDECL null_get_glyph_count(font_object_handle object) ...@@ -863,8 +858,8 @@ static UINT16 CDECL null_get_glyph_count(font_object_handle object)
return 0; return 0;
} }
static INT32 CDECL null_get_glyph_advance(void *key, float emSize, UINT16 index, DWRITE_MEASURING_MODE mode, static INT32 CDECL null_get_glyph_advance(font_object_handle object, float emsize, UINT16 glyph,
BOOL *has_contours) DWRITE_MEASURING_MODE mode, BOOL *has_contours)
{ {
*has_contours = FALSE; *has_contours = FALSE;
return 0; return 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment