[PATCH 11/12] gdi32: Improve the metrics caching function by GGO format.

Byeongsik Jeon bsjeon at hanmail.net
Tue Jan 29 03:12:35 CST 2019


Signed-off-by: Byeongsik Jeon <bsjeon at hanmail.net>
---
Since previous patches have modified the glyph metrics consistency problem,
we can caching the glyph metrics by GGO format.


 dlls/gdi32/freetype.c | 137 +++++++++++++++++++++++++++++-------------
 1 file changed, 96 insertions(+), 41 deletions(-)

diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
index 8c5eb11e66..d3d9e391f7 100644
--- a/dlls/gdi32/freetype.c
+++ b/dlls/gdi32/freetype.c
@@ -306,6 +306,17 @@ typedef struct tagFamily {
     struct list *replacement;
 } Family;
 
+enum GM_type
+{
+    GM_TYPE_MONO,
+    GM_TYPE_GRAY,
+    GM_TYPE_LCD,
+    GM_TYPE_LCD_V,
+    GM_TYPE_OUTLINE,
+    GM_TYPE_NONE
+};
+#define GM_NBTYPES GM_TYPE_NONE
+
 typedef struct {
     GLYPHMETRICS gm;
     ABC          abc;  /* metrics of the unrotated char */
@@ -404,8 +415,8 @@ struct tagGdiFont {
     struct list entry;
     struct list unused_entry;
     unsigned int refcount;
-    GM **gm;
-    DWORD gmsize;
+    GM **gm[GM_NBTYPES];
+    DWORD gmsize[GM_NBTYPES];
     OUTLINETEXTMETRICW *potm;
     DWORD total_kern_pairs;
     KERNINGPAIR *kern_pairs;
@@ -4665,11 +4676,16 @@ static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
 
 static GdiFont *alloc_font(void)
 {
+    DWORD type;
+
     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);
+    for (type = 0; type < GM_NBTYPES; type++)
+    {
+        ret->gmsize[type] = 1;
+        ret->gm[type]    = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM *) );
+        ret->gm[type][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;
@@ -4682,7 +4698,7 @@ static GdiFont *alloc_font(void)
 static void free_font(GdiFont *font)
 {
     CHILD_FONT *child, *child_next;
-    DWORD i;
+    DWORD type, block;
 
     LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
     {
@@ -4700,26 +4716,62 @@ static void free_font(GdiFont *font)
     HeapFree(GetProcessHeap(), 0, font->kern_pairs);
     HeapFree(GetProcessHeap(), 0, font->potm);
     HeapFree(GetProcessHeap(), 0, font->name);
-    for (i = 0; i < font->gmsize; i++)
-        HeapFree(GetProcessHeap(),0,font->gm[i]);
-    HeapFree(GetProcessHeap(), 0, font->gm);
+
+    for (type = 0; type < GM_NBTYPES; type++)
+    {
+        for (block = 0; block < font->gmsize[type]; block++)
+            HeapFree( GetProcessHeap(), 0, font->gm[type][block] );
+        HeapFree( GetProcessHeap(), 0, font->gm[type] );
+    }
+
     HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
     HeapFree(GetProcessHeap(), 0, font);
 }
 
-/* TODO: ggo format support */
-static GM *get_cached_gm_abc_metrics( GdiFont *font, UINT index,
+static UINT get_GM_type( UINT format )
+{
+    switch (format)
+    {
+        case GGO_BITMAP:
+            return GM_TYPE_MONO;
+
+        case GGO_GRAY2_BITMAP:
+        case GGO_GRAY4_BITMAP:
+        case GGO_GRAY8_BITMAP:
+            return GM_TYPE_GRAY;
+
+        case WINE_GGO_HRGB_BITMAP:
+        case WINE_GGO_HBGR_BITMAP:
+            return GM_TYPE_LCD;
+
+        case WINE_GGO_VRGB_BITMAP:
+        case WINE_GGO_VBGR_BITMAP:
+            return GM_TYPE_LCD_V;
+
+        case GGO_NATIVE:
+        case GGO_BEZIER:
+            return GM_TYPE_OUTLINE;
+
+        default:
+            return GM_TYPE_NONE;
+    }
+}
+
+static GM *get_cached_gm_abc_metrics( GdiFont *font, UINT index, UINT format,
                                       GLYPHMETRICS *gm, ABC *abc )
 {
+    UINT type  = get_GM_type( format );
     UINT block = index / GM_BLOCK_SIZE;
     UINT entry = index % GM_BLOCK_SIZE;
     GM *ret = NULL;
 
-    if (block < font->gmsize && font->gm[block] && font->gm[block][entry].init)
+    if (type == GM_TYPE_NONE) return NULL;
+
+    if (block < font->gmsize[type] && font->gm[type][block] && font->gm[type][block][entry].init)
     {
-        *gm  = font->gm[block][entry].gm;
-        *abc = font->gm[block][entry].abc;
-        ret = &font->gm[block][entry];
+        *gm  = font->gm[type][block][entry].gm;
+        *abc = font->gm[type][block][entry].abc;
+        ret = &font->gm[type][block][entry];
 
         TRACE( "cached gm: %u,%u,%s,%d,%d\n", gm->gmBlackBoxX, gm->gmBlackBoxY,
                                               wine_dbgstr_point( &gm->gmptGlyphOrigin ),
@@ -4730,32 +4782,37 @@ static GM *get_cached_gm_abc_metrics( GdiFont *font, UINT index,
     return ret;
 }
 
-static void cache_gm_abc_metrics( GdiFont *font, UINT index,
+static void cache_gm_abc_metrics( GdiFont *font, UINT index, UINT format,
                                   const GLYPHMETRICS *gm, const ABC *abc )
 {
+    UINT type  = get_GM_type( format );
     UINT block = index / GM_BLOCK_SIZE;
     UINT entry = index % GM_BLOCK_SIZE;
 
-    if (block >= font->gmsize)
+    if (type == GM_TYPE_NONE) return;
+
+    if (block >= font->gmsize[type])
     {
         GM **ptr = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
-                                font->gm, (block + 1) * sizeof(GM*) );
+                                font->gm[type], (block + 1) * sizeof(GM*) );
         if (!ptr) return;
 
-        font->gmsize = block + 1;
-        font->gm = ptr;
+        font->gmsize[type] = block + 1;
+        font->gm[type] = ptr;
     }
 
-    if (!font->gm[block])
+    if (!font->gm[type][block])
     {
-        font->gm[block] = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
-                                     sizeof(GM) * GM_BLOCK_SIZE );
-        if (!font->gm[block]) return;
+        font->gm[type][block] = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                           sizeof(GM) * GM_BLOCK_SIZE );
+        if (!font->gm[type][block]) return;
     }
 
-    font->gm[block][entry].gm   = *gm;
-    font->gm[block][entry].abc  = *abc;
-    font->gm[block][entry].init = TRUE;
+    if (font->gm[type][block][entry].init) return;
+
+    font->gm[type][block][entry].gm   = *gm;
+    font->gm[type][block][entry].abc  = *abc;
+    font->gm[type][block][entry].init = TRUE;
 }
 
 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
@@ -7551,17 +7608,13 @@ static DWORD get_ggo_glyph_from_bitmap( FT_GlyphSlot glyph, UINT format, FT_BBox
     return needed;
 }
 
-static FT_Int get_load_flags( UINT format, GdiFont *font )
+static FT_Int get_load_flags( UINT format, BOOL ggo_unhinted, BOOL natural_width )
 {
-    BOOL natural_width;
     FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
 
-    if (format & GGO_UNHINTED)
+    if (ggo_unhinted)
         return load_flags | FT_LOAD_NO_HINTING;
 
-    natural_width = font->font_desc.lf.lfQuality == CLEARTYPE_NATURAL_QUALITY;
-
-    format &= ~(GGO_GLYPH_INDEX | WINE_GGO_METRICS);
     switch (format)
     {
     case WINE_GGO_HRGB_BITMAP:
@@ -7593,7 +7646,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
     DWORD needed = 0;
     FT_Error err;
     FT_BBox bbox;
-    FT_Int load_flags = get_load_flags(format, incoming_font);
+    FT_Int load_flags;
     FT_Matrix transMat = identityMat;
     FT_Matrix transMatUnrotated;
     FT_Matrix transMatTategaki;
@@ -7601,6 +7654,9 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
     BOOL tategaki = (font->name[0] == '@');
     BOOL vertical_metrics;
     BOOL ggo_metrics = format & WINE_GGO_METRICS;
+    BOOL ggo_unhinted = format & GGO_UNHINTED;
+    BOOL natural_width = incoming_font->font_desc.lf.lfQuality == CLEARTYPE_NATURAL_QUALITY;
+    BOOL can_use_cache = is_identity_MAT2(lpmat) && !(ggo_unhinted || natural_width);
 
     TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
 	  buflen, buf, lpmat);
@@ -7617,7 +7673,6 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
             TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index);
         } else
             glyph_index = glyph;
-	format &= ~GGO_GLYPH_INDEX;
         /* TODO: Window also turns off tategaki for glyphs passed in by index
             if their unicode code points fall outside of the range that is
             rotated. */
@@ -7629,10 +7684,10 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
             tategaki = check_unicode_tategaki(glyph);
     }
 
-    format &= ~(WINE_GGO_METRICS | GGO_UNHINTED);
+    format &= ~(WINE_GGO_METRICS | GGO_UNHINTED | GGO_GLYPH_INDEX);
 
-    if (ggo_metrics && is_identity_MAT2(lpmat) &&
-        get_cached_gm_abc_metrics( font, glyph_index, lpgm, abc ))
+    if (ggo_metrics && can_use_cache &&
+        get_cached_gm_abc_metrics( font, glyph_index, format, lpgm, abc ))
         return 1; /* FIXME */
 
     needsTransform = get_transform_matrix( font, tategaki, lpmat,
@@ -7644,6 +7699,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
     if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4 ,0))
         vertical_metrics = FALSE;
 
+    load_flags = get_load_flags( format, ggo_unhinted, natural_width );
     if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
     if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
 
@@ -7698,9 +7754,8 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
                             &transMat, &transMatTategaki, &transMatUnrotated,
                             &gm, abc );
 
-    if ((ggo_metrics || format == GGO_BITMAP || format ==  WINE_GGO_GRAY16_BITMAP) &&
-        is_identity_MAT2(lpmat)) /* don't cache custom transforms */
-        cache_gm_abc_metrics( font, glyph_index, &gm, abc );
+    if (can_use_cache && needed != GDI_ERROR)
+        cache_gm_abc_metrics( font, glyph_index, format, &gm, abc );
 
     if (ggo_metrics || needed != GDI_ERROR)
         *lpgm = gm;
-- 
2.20.1




More information about the wine-devel mailing list