[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