[PATCH 3/5] dwrite: Move glyph box cache to PE side.

Nikolay Sivov nsivov at codeweavers.com
Tue Dec 7 06:59:45 CST 2021


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dwrite/dwrite_private.h |  2 +-
 dlls/dwrite/font.c           | 96 +++++++++++++++++++++---------------
 dlls/dwrite/freetype.c       | 58 +++++++++++-----------
 3 files changed, 88 insertions(+), 68 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_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;
+    }
 
-            if (pFT_Glyph_Copy(glyph, &glyph_copy) == 0) {
-                if (bitmap->simulations & DWRITE_FONT_SIMULATIONS_BOLD)
-                    embolden_glyph(glyph_copy, bitmap->emsize);
+    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_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);
+        /* Includes oblique and user transform. */
+        pFT_Glyph_Transform(glyph, &m, NULL);
     }
 
-    RtlLeaveCriticalSection(&freetype_cs);
+    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);
 }
-- 
2.33.0




More information about the wine-devel mailing list