[vlc-commits] freetype: cache transformed glyph outlines

Francois Cartegnie git at videolan.org
Mon Aug 17 23:43:14 CEST 2020


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Thu Jul 30 19:17:05 2020 +0200| [e2a626989592c8d26537da33bf4075b9615a33d5] | committer: Francois Cartegnie

freetype: cache transformed glyph outlines

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=e2a626989592c8d26537da33bf4075b9615a33d5
---

 modules/text_renderer/Makefile.am            |   1 +
 modules/text_renderer/freetype/ftcache.c     | 108 ++++++++++++++++++++++++++-
 modules/text_renderer/freetype/ftcache.h     |  18 +++++
 modules/text_renderer/freetype/text_layout.c |  65 +++++++++-------
 4 files changed, 165 insertions(+), 27 deletions(-)

diff --git a/modules/text_renderer/Makefile.am b/modules/text_renderer/Makefile.am
index 76e941cf87..1d87479c59 100644
--- a/modules/text_renderer/Makefile.am
+++ b/modules/text_renderer/Makefile.am
@@ -8,6 +8,7 @@ libfreetype_plugin_la_SOURCES = \
 	text_renderer/freetype/freetype.c text_renderer/freetype/freetype.h \
 	text_renderer/freetype/ftcache.c text_renderer/freetype/ftcache.h \
 	text_renderer/freetype/text_layout.c text_renderer/freetype/text_layout.h \
+	text_renderer/freetype/lru.c text_renderer/freetype/lru.h \
         text_renderer/freetype/fonts/backends.h
 
 libfreetype_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS)
diff --git a/modules/text_renderer/freetype/ftcache.c b/modules/text_renderer/freetype/ftcache.c
index d7d90a887e..b4a0268392 100644
--- a/modules/text_renderer/freetype/ftcache.c
+++ b/modules/text_renderer/freetype/ftcache.c
@@ -32,6 +32,7 @@
 
 #include "ftcache.h"
 #include "platform_fonts.h"
+#include "lru.h"
 
 struct vlc_ftcache_t
 {
@@ -42,10 +43,18 @@ struct vlc_ftcache_t
     FTC_Manager       cachemanager;
     FTC_ImageCache    image_cache;
     FTC_CMapCache     charmap_cache;
+    /* Derived glyph cache */
+    vlc_lru *         glyphs_lrucache;
     /* current face properties */
     FT_Long           style_flags;
 };
 
+struct vlc_ftcache_custom_glyph_ref_Rec_
+{
+    FT_Glyph glyph;
+    unsigned refcount;
+};
+
 vlc_face_id_t * vlc_ftcache_GetFaceID( vlc_ftcache_t *ftcache,
                                        const char *psz_fontfile, int i_idx )
 {
@@ -166,6 +175,17 @@ static FT_Error RequestFace( FTC_FaceID face_id, FT_Library library,
     return 0;
 }
 
+static void LRUGlyphRefRelease( void *v )
+{
+    vlc_ftcache_custom_glyph_ref_t ref = (vlc_ftcache_custom_glyph_ref_t) v;
+    assert(ref->refcount);
+    if( --ref->refcount == 0 )
+    {
+        FT_Done_Glyph( ref->glyph );
+        free( ref );
+    }
+}
+
 static void FreeFaceID( void *p_faceid, void *p_obj )
 {
     VLC_UNUSED(p_obj);
@@ -176,6 +196,9 @@ static void FreeFaceID( void *p_faceid, void *p_obj )
 
 void vlc_ftcache_Delete( vlc_ftcache_t *ftcache )
 {
+    if( ftcache->glyphs_lrucache )
+        vlc_lru_Release( ftcache->glyphs_lrucache );
+
     if( ftcache->cachemanager )
         FTC_Manager_Done( ftcache->cachemanager );
 
@@ -196,7 +219,10 @@ vlc_ftcache_t * vlc_ftcache_New( vlc_object_t *obj, FT_Library p_library,
     /* Dictionnaries for fonts */
     vlc_dictionary_init( &ftcache->face_ids, 50 );
 
-    if(FTC_Manager_New( p_library, 4, 8, maxkb << 10,
+    ftcache->glyphs_lrucache = vlc_lru_New( 128, LRUGlyphRefRelease );
+
+    if(!ftcache->glyphs_lrucache ||
+       FTC_Manager_New( p_library, 4, 8, maxkb << 10,
                         RequestFace, ftcache, &ftcache->cachemanager ) ||
        FTC_ImageCache_New( ftcache->cachemanager, &ftcache->image_cache ) ||
        FTC_CMapCache_New( ftcache->cachemanager, &ftcache->charmap_cache ))
@@ -232,3 +258,83 @@ void vlc_ftcache_Glyph_Init( vlc_ftcache_glyph_t *g )
     g->p_glyph = NULL;
     g->ref = NULL;
 }
+
+static vlc_ftcache_custom_glyph_ref_t
+vlc_ftcache_GetCustomGlyph( vlc_ftcache_t *ftcache, const char *psz_key )
+{
+    vlc_ftcache_custom_glyph_ref_t ref = vlc_lru_Get( ftcache->glyphs_lrucache, psz_key );
+    if( ref )
+        ref->refcount++;
+    return ref;
+}
+
+static vlc_ftcache_custom_glyph_ref_t
+vlc_ftcache_AddCustomGlyph( vlc_ftcache_t *ftcache, const char *psz_key, FT_Glyph glyph )
+{
+    assert(!vlc_lru_Get( ftcache->glyphs_lrucache, psz_key ));
+    vlc_ftcache_custom_glyph_ref_t ref = malloc( sizeof(*ref) );
+    if( ref )
+    {
+        ref->refcount = 2;
+        ref->glyph = glyph;
+        vlc_lru_Insert( ftcache->glyphs_lrucache, psz_key, ref );
+    }
+    return ref;
+}
+
+void vlc_ftcache_Custom_Glyph_Release( vlc_ftcache_custom_glyph_t *g )
+{
+    if( g->ref )
+    {
+        assert(g->ref->refcount);
+        if( --g->ref->refcount == 0 )
+        {
+            FT_Done_Glyph( g->ref->glyph );
+            free( g->ref );
+        }
+        vlc_ftcache_Custom_Glyph_Init( g );
+    }
+}
+
+void vlc_ftcache_Custom_Glyph_Init( vlc_ftcache_custom_glyph_t *g )
+{
+    g->p_glyph = NULL;
+    g->ref = NULL;
+}
+
+FT_Glyph vlc_ftcache_GetOutlinedGlyph( vlc_ftcache_t *ftcache, const vlc_face_id_t *faceid,
+                                       FT_UInt index, const vlc_ftcache_metrics_t *metrics,
+                                       FT_Long style, int radius, const FT_Glyph sourceglyph,
+                                       int(*createOutline)(FT_Glyph, FT_Glyph *, void *),
+                                       void *priv,
+                                       vlc_ftcache_custom_glyph_ref_t *p_ref )
+{
+    char *psz_key;
+    if( asprintf( &psz_key, "%s#%d#%d#%d,%d,%d,%lx,%d",
+                  faceid->psz_filename, faceid->idx,
+                  faceid->charmap_index, index,
+                  metrics->width_px, metrics->height_px, style, radius ) < 0 )
+    {
+        *p_ref = NULL;
+        return NULL;
+    }
+
+    FT_Glyph glyph = NULL;
+    *p_ref = vlc_ftcache_GetCustomGlyph( ftcache, psz_key );
+    if( *p_ref )
+    {
+        glyph = (*p_ref)->glyph;
+    }
+    else
+    {
+        if( !createOutline( sourceglyph, &glyph, priv ) )
+            *p_ref = vlc_ftcache_AddCustomGlyph( ftcache, psz_key, glyph );
+        if( !*p_ref )
+        {
+            FT_Done_Glyph( glyph );
+            return NULL;
+        }
+    }
+    free( psz_key );
+    return glyph;
+}
diff --git a/modules/text_renderer/freetype/ftcache.h b/modules/text_renderer/freetype/ftcache.h
index cb6d12d740..ff997f9157 100644
--- a/modules/text_renderer/freetype/ftcache.h
+++ b/modules/text_renderer/freetype/ftcache.h
@@ -67,6 +67,24 @@ FT_Face vlc_ftcache_LoadFaceByID( vlc_ftcache_t *, vlc_face_id_t *faceid,
                                   const vlc_ftcache_metrics_t * );
 int vlc_ftcache_LoadFaceByIDNoSize( vlc_ftcache_t *ftcache, vlc_face_id_t *faceid );
 
+/* Custom modified glyphs cache. Similar to native caching.
+ * Stores and returns a refcounted copy of the original glyph. */
+typedef struct vlc_ftcache_custom_glyph_ref_Rec_ * vlc_ftcache_custom_glyph_ref_t;
+typedef struct
+{
+    FT_Glyph p_glyph;
+    vlc_ftcache_custom_glyph_ref_t ref;
+} vlc_ftcache_custom_glyph_t;
+
+FT_Glyph vlc_ftcache_GetOutlinedGlyph( vlc_ftcache_t *ftcache, const vlc_face_id_t *faceid,
+                                       FT_UInt index, const vlc_ftcache_metrics_t *,
+                                       FT_Long style, int radius, const FT_Glyph sourceglyph,
+                                       int(*createOutline)(FT_Glyph, FT_Glyph *, void *), void *,
+                                       vlc_ftcache_custom_glyph_ref_t * );
+
+void vlc_ftcache_Custom_Glyph_Init( vlc_ftcache_custom_glyph_t * );
+void vlc_ftcache_Custom_Glyph_Release( vlc_ftcache_custom_glyph_t * );
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/modules/text_renderer/freetype/text_layout.c b/modules/text_renderer/freetype/text_layout.c
index 127d53d151..448bf750d0 100644
--- a/modules/text_renderer/freetype/text_layout.c
+++ b/modules/text_renderer/freetype/text_layout.c
@@ -118,7 +118,7 @@ typedef struct run_desc_t
 typedef struct glyph_bitmaps_t
 {
     vlc_ftcache_glyph_t cglyph;
-    FT_Glyph p_outline;
+    vlc_ftcache_custom_glyph_t coutline;
     FT_Glyph p_shadow;
     FT_BBox  glyph_bbox;
     FT_BBox  outline_bbox;
@@ -939,10 +939,8 @@ static int RemoveZeroWidthCharacters( filter_t *p_filter, paragraph_t *p_paragra
          || ( ch >= 0x200b && ch <= 0x200f ) )
         {
             glyph_bitmaps_t *p_bitmaps = p_paragraph->p_glyph_bitmaps + i;
-            if( p_bitmaps->p_outline )
-                FT_Done_Glyph( p_bitmaps->p_outline );
+            vlc_ftcache_Custom_Glyph_Release( &p_bitmaps->coutline );
             vlc_ftcache_Glyph_Release( p_sys->ftcache, &p_bitmaps->cglyph );
-            p_bitmaps->p_outline = 0;
             p_bitmaps->p_shadow = 0;
             p_bitmaps->i_x_advance = 0;
             p_bitmaps->i_y_advance = 0;
@@ -975,13 +973,22 @@ static void ReleaseGlyphBitMaps(filter_t *p_filter, glyph_bitmaps_t *p_bitmaps)
     filter_sys_t *p_sys = p_filter->p_sys;
     if( p_bitmaps->p_shadow &&
         p_bitmaps->p_shadow != p_bitmaps->cglyph.p_glyph &&
-        p_bitmaps->p_shadow != p_bitmaps->p_outline )
+        p_bitmaps->p_shadow != p_bitmaps->coutline.p_glyph )
         FT_Done_Glyph( p_bitmaps->p_shadow );
-    if( p_bitmaps->p_outline )
-        FT_Done_Glyph( p_bitmaps->p_outline );
+    vlc_ftcache_Custom_Glyph_Release( &p_bitmaps->coutline );
     vlc_ftcache_Glyph_Release( p_sys->ftcache, &p_bitmaps->cglyph );
 }
 
+static int CreateOutlinedGlyph( FT_Glyph src, FT_Glyph *dest, void *priv )
+{
+    filter_t *p_filter = priv;
+    filter_sys_t *p_sys = p_filter->p_sys;
+    if(FT_Glyph_StrokeBorder( &src, p_sys->p_stroker, 0, 0 ))
+        return -1;
+    *dest = src;
+    return 0;
+}
+
 /**
  * Load the glyphs of a paragraph. When shaping with HarfBuzz the glyph indices
  * have already been determined at this point, as well as the advance values.
@@ -1027,13 +1034,14 @@ static int LoadGlyphs( filter_t *p_filter, paragraph_t *p_paragraph,
             else continue; /* can't do much from now */
         }
 
+        int i_stroker_radius = 0;
         if( p_sys->p_stroker && (p_style->i_style_flags & STYLE_OUTLINE) )
         {
             double f_outline_thickness = p_sys->i_outline_thickness / 100.0;
             f_outline_thickness = VLC_CLIP( f_outline_thickness, 0.0, 0.5 );
-            int i_radius = ( metrics.height_px << 6 ) * f_outline_thickness;
+            i_stroker_radius = ( metrics.height_px << 6 ) * f_outline_thickness;
             FT_Stroker_Set( p_sys->p_stroker,
-                            i_radius,
+                            i_stroker_radius,
                             FT_STROKER_LINECAP_ROUND,
                             FT_STROKER_LINEJOIN_ROUND, 0 );
         }
@@ -1054,7 +1062,7 @@ static int LoadGlyphs( filter_t *p_filter, paragraph_t *p_paragraph,
 #define SKIP_GLYPH( p_bitmaps ) \
     { \
         vlc_ftcache_Glyph_Init( &p_bitmaps->cglyph );\
-        p_bitmaps->p_outline = 0; \
+        vlc_ftcache_Custom_Glyph_Init( &p_bitmaps->coutline ); \
         p_bitmaps->p_shadow = 0; \
         p_bitmaps->i_x_advance = 0; \
         p_bitmaps->i_y_advance = 0; \
@@ -1128,15 +1136,17 @@ static int LoadGlyphs( filter_t *p_filter, paragraph_t *p_paragraph,
             /* !warn: style STYLE_OUTLINE != glyph FORMAT_OUTLINE */
             if( p_sys->p_stroker && (p_style->i_style_flags & STYLE_OUTLINE) )
             {
-                p_bitmaps->p_outline = p_bitmaps->cglyph.p_glyph;
-                if( FT_Glyph_StrokeBorder( &p_bitmaps->p_outline,
-                                           p_sys->p_stroker, 0, 0 ) )
-                    p_bitmaps->p_outline = 0;
+                p_bitmaps->coutline.p_glyph =
+                    vlc_ftcache_GetOutlinedGlyph( p_sys->ftcache, p_run->p_faceid, i_glyph_index,
+                                                  &metrics, style_flags, i_stroker_radius,
+                                                  p_bitmaps->cglyph.p_glyph,
+                                                  CreateOutlinedGlyph, p_filter,
+                                                  &p_bitmaps->coutline.ref );
             }
 
             if( p_style->i_shadow_alpha != STYLE_ALPHA_TRANSPARENT )
-                p_bitmaps->p_shadow = p_bitmaps->p_outline ?
-                                      p_bitmaps->p_outline : p_bitmaps->cglyph.p_glyph;
+                p_bitmaps->p_shadow = p_bitmaps->coutline.p_glyph ?
+                                      p_bitmaps->coutline.p_glyph : p_bitmaps->cglyph.p_glyph;
 
             if( b_overwrite_advance )
             {
@@ -1265,12 +1275,15 @@ static int LayoutLine( filter_t *p_filter,
         vlc_ftcache_Glyph_Release( p_sys->ftcache, &p_bitmaps->cglyph );
         p_bitmaps->cglyph.p_glyph = bitmapglyph;
 
-        if( p_bitmaps->p_outline &&
-            FT_Glyph_To_Bitmap( &p_bitmaps->p_outline, FT_RENDER_MODE_NORMAL,
-                                &pen_new, 1 ) )
+        if( p_bitmaps->coutline.p_glyph )
         {
-            FT_Done_Glyph( p_bitmaps->p_outline );
-            p_bitmaps->p_outline = 0;
+            bitmapglyph = p_bitmaps->coutline.p_glyph;
+            if( FT_Glyph_To_Bitmap( &bitmapglyph,
+                                    FT_RENDER_MODE_NORMAL,
+                                    &pen_new, 0 ) )
+                bitmapglyph = NULL;
+            vlc_ftcache_Custom_Glyph_Release( &p_bitmaps->coutline );
+            p_bitmaps->coutline.p_glyph = bitmapglyph;
         }
 
         FT_Glyph_Get_CBox( p_bitmaps->cglyph.p_glyph, FT_GLYPH_BBOX_PIXELS,
@@ -1278,11 +1291,11 @@ static int LayoutLine( filter_t *p_filter,
         FixGlyph( p_bitmaps->cglyph.p_glyph, &p_bitmaps->glyph_bbox,
                   p_bitmaps->i_x_advance, p_bitmaps->i_y_advance,
                   &pen_new );
-        if( p_bitmaps->p_outline )
+        if( p_bitmaps->coutline.p_glyph )
         {
-            FT_Glyph_Get_CBox( p_bitmaps->p_outline, FT_GLYPH_BBOX_PIXELS,
+            FT_Glyph_Get_CBox( p_bitmaps->coutline.p_glyph, FT_GLYPH_BBOX_PIXELS,
                                &p_bitmaps->outline_bbox );
-            FixGlyph( p_bitmaps->p_outline, &p_bitmaps->outline_bbox,
+            FixGlyph( p_bitmaps->coutline.p_glyph, &p_bitmaps->outline_bbox,
                       p_bitmaps->i_x_advance, p_bitmaps->i_y_advance,
                       &pen_new );
         }
@@ -1338,7 +1351,7 @@ static int LayoutLine( filter_t *p_filter,
         }
 
         p_ch->p_glyph = ( FT_BitmapGlyph ) p_bitmaps->cglyph.p_glyph;
-        p_ch->p_outline = ( FT_BitmapGlyph ) p_bitmaps->p_outline;
+        p_ch->p_outline = ( FT_BitmapGlyph ) p_bitmaps->coutline.p_glyph;
         p_ch->p_shadow = ( FT_BitmapGlyph ) p_bitmaps->p_shadow;
 
         p_ch->i_line_thickness = i_line_thickness;
@@ -1346,7 +1359,7 @@ static int LayoutLine( filter_t *p_filter,
 
         /* Compute bounding box for all glyphs */
         p_ch->bbox = p_bitmaps->glyph_bbox;
-        if( p_bitmaps->p_outline )
+        if( p_bitmaps->coutline.p_glyph )
             BBoxEnlarge( &p_ch->bbox, &p_bitmaps->outline_bbox );
         if( p_bitmaps->p_shadow )
             BBoxEnlarge( &p_ch->bbox, &p_bitmaps->shadow_bbox );



More information about the vlc-commits mailing list