From b3ad9000c04c5e57d65d955c1669402fb617c79d Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Tue, 7 Dec 2021 15:59:45 +0300 Subject: [PATCH] dwrite: Move glyph box cache to PE side. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/dwrite/dwrite_private.h | 2 +- dlls/dwrite/font.c | 96 +++++++++++++++++++++--------------- dlls/dwrite/freetype.c | 62 ++++++++++++----------- 3 files changed, 90 insertions(+), 70 deletions(-) diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index ba634c99917..b166766a167 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -734,7 +734,7 @@ struct font_backend_funcs UINT16 (CDECL *get_glyph_count)(font_object_handle object); INT32 (CDECL *get_glyph_advance)(font_object_handle object, float em_size, UINT16 glyph, DWRITE_MEASURING_MODE measuring_mode, BOOL *has_contours); - void (CDECL *get_glyph_bbox)(void *key, struct dwrite_glyphbitmap *bitmap_desc); + void (CDECL *get_glyph_bbox)(font_object_handle object, struct dwrite_glyphbitmap *bitmap_desc); BOOL (CDECL *get_glyph_bitmap)(void *key, struct dwrite_glyphbitmap *bitmap_desc); void (CDECL *get_design_glyph_metrics)(font_object_handle object, UINT16 upem, UINT16 ascent, unsigned int simulations, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics); diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index 205b2f8c0f1..c6ef61f7fe3 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -47,11 +47,6 @@ static const FLOAT RECOMMENDED_NATURAL_PPEM = 20.0f; static const struct font_backend_funcs *font_funcs; -void dwrite_fontface_get_glyph_bbox(IDWriteFontFace *fontface, struct dwrite_glyphbitmap *bitmap) -{ - font_funcs->get_glyph_bbox(fontface, bitmap); -} - struct cache_key { float size; @@ -65,40 +60,28 @@ struct cache_entry struct list mru; struct cache_key key; float advance; + RECT bbox; unsigned int has_contours : 1; unsigned int has_advance : 1; + unsigned int has_bbox : 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) +static struct cache_entry * fontface_get_cache_entry(struct dwrite_fontface *fontface, const struct cache_key *key) { - struct cache_key key = { .size = fontsize, .glyph = glyph, .mode = mode }; struct cache_entry *entry, *old_entry; + struct wine_rb_entry *e; size_t size; - BOOL value; - if (!(entry = fontface_get_cache_entry(fontface, &key))) + if (!(e = wine_rb_get(&fontface->cache.tree, key))) { - if (!(entry = calloc(1, sizeof(*entry)))) - return 0.0f; - entry->key = key; + if (!(entry = calloc(1, sizeof(*entry)))) return NULL; + entry->key = *key; + list_init(&entry->mru); size = fontface_get_cache_entry_size(entry); if ((fontface->cache.size + size > fontface->cache.max_size) && !list_empty(&fontface->cache.mru)) @@ -110,16 +93,33 @@ static float fontface_get_glyph_advance(struct dwrite_fontface *fontface, float 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; + free(entry); + return NULL; } fontface->cache.size += size; } + else + entry = WINE_RB_ENTRY_VALUE(e, struct cache_entry, entry); + + list_remove(&entry->mru); + list_add_head(&fontface->cache.mru, &entry->mru); + + return 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; + BOOL value; + + if (!(entry = fontface_get_cache_entry(fontface, &key))) + return 0.0f; if (!entry->has_advance) { @@ -132,6 +132,32 @@ static float fontface_get_glyph_advance(struct dwrite_fontface *fontface, float return entry->advance; } +void dwrite_fontface_get_glyph_bbox(IDWriteFontFace *iface, struct dwrite_glyphbitmap *bitmap) +{ + struct cache_key key = { .size = bitmap->emsize, .glyph = bitmap->glyph, .mode = DWRITE_MEASURING_MODE_NATURAL }; + struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface); + struct cache_entry *entry; + + EnterCriticalSection(&fontface->cs); + /* For now bypass cache for transformed cases. */ + if (bitmap->m && memcmp(bitmap->m, &identity, sizeof(*bitmap->m))) + { + font_funcs->get_glyph_bbox(fontface->get_font_object(fontface), bitmap); + } + else if ((entry = fontface_get_cache_entry(fontface, &key))) + { + if (entry->has_bbox) + bitmap->bbox = entry->bbox; + else + { + font_funcs->get_glyph_bbox(fontface->get_font_object(fontface), bitmap); + entry->bbox = bitmap->bbox; + entry->has_bbox = 1; + } + } + LeaveCriticalSection(&fontface->cs); +} + 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); @@ -5819,8 +5845,6 @@ static UINT32 get_glyph_bitmap_pitch(DWRITE_RENDERING_MODE1 rendering_mode, INT static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds) { struct dwrite_glyphbitmap glyph_bitmap; - IDWriteFontFace4 *fontface; - HRESULT hr; UINT32 i; if (analysis->flags & RUNANALYSIS_BOUNDS_READY) { @@ -5831,12 +5855,8 @@ static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *a if (analysis->run.isSideways) FIXME("sideways runs are not supported.\n"); - hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface); - if (FAILED(hr)) - WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr); - memset(&glyph_bitmap, 0, sizeof(glyph_bitmap)); - glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface); + glyph_bitmap.simulations = IDWriteFontFace_GetSimulations(analysis->run.fontFace); glyph_bitmap.emsize = analysis->run.fontEmSize; glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode); if (analysis->flags & RUNANALYSIS_USE_TRANSFORM) @@ -5847,7 +5867,7 @@ static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *a UINT32 bitmap_size; glyph_bitmap.glyph = analysis->run.glyphIndices[i]; - font_funcs->get_glyph_bbox(fontface, &glyph_bitmap); + dwrite_fontface_get_glyph_bbox(analysis->run.fontFace, &glyph_bitmap); bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) * (bbox->bottom - bbox->top); @@ -5858,8 +5878,6 @@ static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *a UnionRect(&analysis->bounds, &analysis->bounds, bbox); } - IDWriteFontFace4_Release(fontface); - analysis->flags |= RUNANALYSIS_BOUNDS_READY; *bounds = analysis->bounds; } @@ -5946,7 +5964,7 @@ static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis) BOOL is_1bpp; glyph_bitmap.glyph = analysis->run.glyphIndices[i]; - font_funcs->get_glyph_bbox(fontface, &glyph_bitmap); + dwrite_fontface_get_glyph_bbox(analysis->run.fontFace, &glyph_bitmap); if (IsRectEmpty(bbox)) continue; diff --git a/dlls/dwrite/freetype.c b/dlls/dwrite/freetype.c index dede7c46c9c..34b08cfd2a4 100644 --- a/dlls/dwrite/freetype.c +++ b/dlls/dwrite/freetype.c @@ -76,6 +76,7 @@ MAKE_FUNCPTR(FT_Done_FreeType); MAKE_FUNCPTR(FT_Done_Glyph); MAKE_FUNCPTR(FT_Done_Size); MAKE_FUNCPTR(FT_Get_First_Char); +MAKE_FUNCPTR(FT_Get_Glyph); MAKE_FUNCPTR(FT_Get_Kerning); MAKE_FUNCPTR(FT_Get_Sfnt_Table); MAKE_FUNCPTR(FT_Glyph_Copy); @@ -184,6 +185,7 @@ static BOOL init_freetype(void) LOAD_FUNCPTR(FT_Done_Glyph) LOAD_FUNCPTR(FT_Done_Size) LOAD_FUNCPTR(FT_Get_First_Char) + LOAD_FUNCPTR(FT_Get_Glyph) LOAD_FUNCPTR(FT_Get_Kerning) LOAD_FUNCPTR(FT_Get_Sfnt_Table) LOAD_FUNCPTR(FT_Glyph_Copy) @@ -572,7 +574,7 @@ static BOOL is_face_scalable(void *key) return FALSE; } -static BOOL get_glyph_transform(void *key, struct dwrite_glyphbitmap *bitmap, FT_Matrix *ret) +static BOOL get_glyph_transform(struct dwrite_glyphbitmap *bitmap, FT_Matrix *ret) { FT_Matrix m; @@ -583,7 +585,7 @@ static BOOL get_glyph_transform(void *key, struct dwrite_glyphbitmap *bitmap, FT /* Some fonts provide mostly bitmaps and very few outlines, for example for .notdef. Disable transform if that's the case. */ - if (!is_face_scalable(key) || (!bitmap->m && !bitmap->simulations)) + if (!bitmap->m && !bitmap->simulations) return FALSE; if (bitmap->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) { @@ -602,42 +604,42 @@ static BOOL get_glyph_transform(void *key, struct dwrite_glyphbitmap *bitmap, FT return TRUE; } -static void CDECL freetype_get_glyph_bbox(void *key, struct dwrite_glyphbitmap *bitmap) +static void CDECL freetype_get_glyph_bbox(font_object_handle object, struct dwrite_glyphbitmap *bitmap) { - FTC_ImageTypeRec imagetype; + FT_Face face = object; + FT_Glyph glyph = NULL; FT_BBox bbox = { 0 }; BOOL needs_transform; - FT_Glyph glyph; FT_Matrix m; + FT_Size size; - RtlEnterCriticalSection(&freetype_cs); + SetRectEmpty(&bitmap->bbox); - needs_transform = get_glyph_transform(key, bitmap, &m); + if (!(size = freetype_set_face_size(face, bitmap->emsize))) + return; - imagetype.face_id = key; - imagetype.width = 0; - imagetype.height = bitmap->emsize; - imagetype.flags = needs_transform ? FT_LOAD_NO_BITMAP : FT_LOAD_DEFAULT; + needs_transform = FT_IS_SCALABLE(face) && get_glyph_transform(bitmap, &m); - if (pFTC_ImageCache_Lookup(image_cache, &imagetype, bitmap->glyph, &glyph, NULL) == 0) { - if (needs_transform) { - FT_Glyph glyph_copy; - - if (pFT_Glyph_Copy(glyph, &glyph_copy) == 0) { - if (bitmap->simulations & DWRITE_FONT_SIMULATIONS_BOLD) - embolden_glyph(glyph_copy, bitmap->emsize); - - /* Includes oblique and user transform. */ - pFT_Glyph_Transform(glyph_copy, &m, NULL); - pFT_Glyph_Get_CBox(glyph_copy, FT_GLYPH_BBOX_PIXELS, &bbox); - pFT_Done_Glyph(glyph_copy); - } - } - else - pFT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &bbox); + if (pFT_Load_Glyph(face, bitmap->glyph, needs_transform ? FT_LOAD_NO_BITMAP : 0)) + { + WARN("Failed to load glyph %u.\n", bitmap->glyph); + pFT_Done_Size(size); + return; } - RtlLeaveCriticalSection(&freetype_cs); + pFT_Get_Glyph(face->glyph, &glyph); + if (needs_transform) + { + if (bitmap->simulations & DWRITE_FONT_SIMULATIONS_BOLD) + embolden_glyph(glyph, bitmap->emsize); + + /* Includes oblique and user transform. */ + pFT_Glyph_Transform(glyph, &m, NULL); + } + + pFT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &bbox); + pFT_Done_Glyph(glyph); + pFT_Done_Size(size); /* flip Y axis */ SetRect(&bitmap->bbox, bbox.xMin, -bbox.yMax, bbox.xMax, -bbox.yMin); @@ -744,7 +746,7 @@ static BOOL CDECL freetype_get_glyph_bitmap(void *key, struct dwrite_glyphbitmap RtlEnterCriticalSection(&freetype_cs); - needs_transform = get_glyph_transform(key, bitmap, &m); + needs_transform = is_face_scalable(key) && get_glyph_transform(bitmap, &m); imagetype.face_id = key; imagetype.width = 0; @@ -865,7 +867,7 @@ static INT32 CDECL null_get_glyph_advance(font_object_handle object, float emsiz return 0; } -static void CDECL null_get_glyph_bbox(void *key, struct dwrite_glyphbitmap *bitmap) +static void CDECL null_get_glyph_bbox(font_object_handle object, struct dwrite_glyphbitmap *bitmap) { SetRectEmpty(&bitmap->bbox); }