[vlc-commits] freetype: use cache subsystem
Francois Cartegnie
git at videolan.org
Mon Aug 17 23:43:11 CEST 2020
vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Wed Jul 22 09:58:33 2020 +0200| [151ccdce37fc54780b1a3262dde7be910ae0fbef] | committer: Francois Cartegnie
freetype: use cache subsystem
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=151ccdce37fc54780b1a3262dde7be910ae0fbef
---
modules/text_renderer/Makefile.am | 1 +
modules/text_renderer/freetype/fonts/dwrite.cpp | 2 +-
modules/text_renderer/freetype/fonts/win32.c | 2 +-
modules/text_renderer/freetype/freetype.c | 35 +--
modules/text_renderer/freetype/freetype.h | 21 +-
modules/text_renderer/freetype/ftcache.c | 234 ++++++++++++++++++
modules/text_renderer/freetype/ftcache.h | 74 ++++++
modules/text_renderer/freetype/platform_fonts.c | 128 ++++------
modules/text_renderer/freetype/platform_fonts.h | 6 +-
modules/text_renderer/freetype/text_layout.c | 312 +++++++++++++-----------
10 files changed, 569 insertions(+), 246 deletions(-)
diff --git a/modules/text_renderer/Makefile.am b/modules/text_renderer/Makefile.am
index ef521d4c53..76e941cf87 100644
--- a/modules/text_renderer/Makefile.am
+++ b/modules/text_renderer/Makefile.am
@@ -6,6 +6,7 @@ text_LTLIBRARIES = libtdummy_plugin.la
libfreetype_plugin_la_SOURCES = \
text_renderer/freetype/platform_fonts.c text_renderer/freetype/platform_fonts.h \
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/fonts/backends.h
diff --git a/modules/text_renderer/freetype/fonts/dwrite.cpp b/modules/text_renderer/freetype/fonts/dwrite.cpp
index 1e46381dfc..13e44ac76e 100644
--- a/modules/text_renderer/freetype/fonts/dwrite.cpp
+++ b/modules/text_renderer/freetype/fonts/dwrite.cpp
@@ -790,7 +790,7 @@ extern "C" vlc_family_t *DWrite_GetFallbacks( vlc_font_select_t *fs, const char
if( !p_fallback || !p_fallback->p_fonts )
goto done;
- if( !GetFace( fs, p_fallback->p_fonts, codepoint ) )
+ if( !CheckFace( fs, p_fallback->p_fonts, codepoint ) )
goto done;
p_family = NewFamily( fs, psz_fallback, NULL, NULL, NULL );
diff --git a/modules/text_renderer/freetype/fonts/win32.c b/modules/text_renderer/freetype/fonts/win32.c
index bed26294c1..f2ab4cf769 100644
--- a/modules/text_renderer/freetype/fonts/win32.c
+++ b/modules/text_renderer/freetype/fonts/win32.c
@@ -555,7 +555,7 @@ vlc_family_t *Win32_GetFallbacks( vlc_font_select_t *fs, const char *psz_family,
if( !p_uniscribe || !p_uniscribe->p_fonts )
goto done;
- if( !GetFace( fs, p_uniscribe->p_fonts, codepoint ) )
+ if( !CheckFace( fs, p_uniscribe->p_fonts, codepoint ) )
goto done;
p_family = NewFamily( fs, psz_uniscribe, NULL, NULL, NULL );
diff --git a/modules/text_renderer/freetype/freetype.c b/modules/text_renderer/freetype/freetype.c
index c800a8cff2..a5f34547c3 100644
--- a/modules/text_renderer/freetype/freetype.c
+++ b/modules/text_renderer/freetype/freetype.c
@@ -83,6 +83,8 @@ static void Destroy( vlc_object_t * );
#define SHADOW_COLOR_TEXT N_("Shadow color")
#define SHADOW_ANGLE_TEXT N_("Shadow angle")
#define SHADOW_DISTANCE_TEXT N_("Shadow distance")
+#define CACHE_SIZE_TEXT N_("Cache size")
+#define CACHE_SIZE_LONGTEXT N_("Cache size in kBytes")
#define TEXT_DIRECTION_TEXT N_("Text direction")
#define TEXT_DIRECTION_LONGTEXT N_("Paragraph base direction for the Unicode bi-directional algorithm.")
@@ -182,6 +184,10 @@ vlc_module_begin ()
SHADOW_DISTANCE_TEXT, NULL, false )
change_safe()
+ add_integer_with_range( "freetype-cache-size", 200, 25, (UINT32_MAX >> 10),
+ CACHE_SIZE_TEXT, CACHE_SIZE_LONGTEXT, true )
+ change_safe()
+
add_obsolete_integer( "freetype-fontsize" );
add_obsolete_integer( "freetype-rel-fontsize" );
add_obsolete_integer( "freetype-effect" );
@@ -1168,11 +1174,11 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region_out,
UpdateDefaultLiveStyles( p_filter );
int i_font_default_size = ConvertToLiveSize( p_filter, p_sys->p_default_style );
- if( !p_sys->p_face || i_font_default_size != p_sys->i_font_default_size )
+ if( !p_sys->p_faceid || i_font_default_size != p_sys->i_font_default_size )
{
/* Update the default face to reflect changes in video size or text scaling */
- p_sys->p_face = SelectAndLoadFace( p_filter, p_sys->p_default_style, ' ' );
- if( !p_sys->p_face )
+ p_sys->p_faceid = SelectAndLoadFace( p_filter, p_sys->p_default_style, ' ' );
+ if( !p_sys->p_faceid )
{
msg_Err( p_filter, "Render(): Error loading default face" );
return VLC_EGENERIC;
@@ -1353,13 +1359,6 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region_out,
return rv;
}
-static void FreeFace( void *p_face, void *p_obj )
-{
- VLC_UNUSED( p_obj );
-
- FT_Done_Face( ( FT_Face ) p_face );
-}
-
/*****************************************************************************
* Create: allocates osd-text video thread output method
*****************************************************************************
@@ -1389,8 +1388,10 @@ static int Create( vlc_object_t *p_this )
p_sys->p_stroker = NULL;
}
- /* Dictionnaries for fonts */
- vlc_dictionary_init( &p_sys->face_map, 50 );
+ p_sys->ftcache = vlc_ftcache_New( p_this, p_sys->p_library,
+ var_InheritInteger( p_this, "freetype-cache-size" ) );
+ if( !p_sys->ftcache )
+ goto error;
p_sys->i_scale = 100;
@@ -1432,8 +1433,8 @@ static int Create( vlc_object_t *p_this )
if( LoadFontsFromAttachments( p_filter ) == VLC_ENOMEM )
goto error;
- p_sys->p_face = SelectAndLoadFace( p_filter, p_sys->p_default_style, ' ' );
- if( !p_sys->p_face )
+ p_sys->p_faceid = SelectAndLoadFace( p_filter, p_sys->p_default_style, ' ' );
+ if( !p_sys->p_faceid )
{
msg_Err( p_filter, "Error loading default face %s",
p_sys->p_default_style->psz_fontname );
@@ -1471,9 +1472,6 @@ static void Destroy( vlc_object_t *p_this )
text_style_Delete( p_sys->p_default_style );
text_style_Delete( p_sys->p_forced_style );
- /* Fonts dicts */
- vlc_dictionary_clear( &p_sys->face_map, FreeFace, p_filter );
-
/* Attachments */
if( p_sys->pp_font_attachments )
{
@@ -1490,6 +1488,9 @@ static void Destroy( vlc_object_t *p_this )
if( p_sys->p_stroker )
FT_Stroker_Done( p_sys->p_stroker );
+ if( p_sys->ftcache )
+ vlc_ftcache_Delete( p_sys->ftcache );
+
FT_Done_FreeType( p_sys->p_library );
free( p_sys );
diff --git a/modules/text_renderer/freetype/freetype.h b/modules/text_renderer/freetype/freetype.h
index 44d91aecd3..aff536b8e1 100644
--- a/modules/text_renderer/freetype/freetype.h
+++ b/modules/text_renderer/freetype/freetype.h
@@ -74,8 +74,11 @@ typedef uint32_t uni_char_t;
#define FT_GLYPH_BBOX_GRIDFIT ft_glyph_bbox_gridfit
#define FT_GLYPH_BBOX_TRUNCATE ft_glyph_bbox_truncate
#define FT_GLYPH_BBOX_PIXELS ft_glyph_bbox_pixels
+ #define FT_ENCODING_UNICODE ft_encoding_unicode
#endif
+#include "ftcache.h"
+
typedef struct vlc_font_select_t vlc_font_select_t;
/*****************************************************************************
@@ -89,7 +92,7 @@ typedef struct vlc_family_t vlc_family_t;
typedef struct
{
FT_Library p_library; /* handle to library */
- FT_Face p_face; /* handle to face object */
+ vlc_face_id_t *p_faceid; /* handle to face object */
FT_Stroker p_stroker; /* handle to path stroker object */
text_style_t *p_default_style;
@@ -106,15 +109,13 @@ typedef struct
input_attachment_t **pp_font_attachments;
int i_font_attachments;
- /** Font face cache */
- vlc_dictionary_t face_map;
-
/* Current scaling of the text, default is 100 (%) */
int i_scale;
int i_font_default_size;
int i_outline_thickness;
vlc_font_select_t *fs;
+ vlc_ftcache_t *ftcache;
} filter_sys_t;
@@ -125,8 +126,8 @@ typedef struct
* \param p_style the requested style (fonts can be different for italic or bold) [IN]
* \param codepoint the codepoint needed [IN]
*/
-FT_Face SelectAndLoadFace( filter_t *p_filter, const text_style_t *p_style,
- uni_char_t codepoint );
+vlc_face_id_t * SelectAndLoadFace( filter_t *p_filter, const text_style_t *p_style,
+ uni_char_t codepoint );
static inline void BBoxInit( FT_BBox *p_box )
{
@@ -144,5 +145,13 @@ static inline void BBoxEnlarge( FT_BBox *p_max, const FT_BBox *p )
p_max->yMax = __MAX(p_max->yMax, p->yMax);
}
+static inline int GetFontWidthForStyle( const text_style_t *p_style, int i_size )
+{
+ if( p_style->i_style_flags & STYLE_HALFWIDTH )
+ i_size /= 2;
+ else if( p_style->i_style_flags & STYLE_DOUBLEWIDTH )
+ i_size *= 2;
+ return i_size;
+}
#endif
diff --git a/modules/text_renderer/freetype/ftcache.c b/modules/text_renderer/freetype/ftcache.c
new file mode 100644
index 0000000000..d7d90a887e
--- /dev/null
+++ b/modules/text_renderer/freetype/ftcache.c
@@ -0,0 +1,234 @@
+/*****************************************************************************
+ * ftcache.c : Font Face and glyph cache freetype2
+ *****************************************************************************
+ * Copyright (C) 2020 - VideoLabs, VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_filter.h>
+#include <vlc_text_style.h>
+
+/* Freetype */
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+
+#include "ftcache.h"
+#include "platform_fonts.h"
+
+struct vlc_ftcache_t
+{
+ vlc_object_t *obj;
+ /** Font face cache */
+ vlc_dictionary_t face_ids;
+ FTC_ScalerRec scaler;
+ FTC_Manager cachemanager;
+ FTC_ImageCache image_cache;
+ FTC_CMapCache charmap_cache;
+ /* current face properties */
+ FT_Long style_flags;
+};
+
+vlc_face_id_t * vlc_ftcache_GetFaceID( vlc_ftcache_t *ftcache,
+ const char *psz_fontfile, int i_idx )
+{
+ char *psz_key;
+ if( asprintf( &psz_key, "%s#%d",
+ psz_fontfile, i_idx ) < 0 )
+ return NULL;
+
+ vlc_face_id_t *faceid = vlc_dictionary_value_for_key( &ftcache->face_ids, psz_key );
+ if( !faceid )
+ {
+ faceid = malloc(sizeof(vlc_face_id_t));
+ if( faceid )
+ {
+ faceid->idx = i_idx;
+ faceid->psz_filename = strdup(psz_fontfile);
+ if( faceid->psz_filename )
+ {
+ faceid->charmap_index = -1;
+ vlc_dictionary_insert( &ftcache->face_ids, psz_key, faceid );
+ }
+ else
+ {
+ free( faceid );
+ faceid = NULL;
+ }
+ }
+ }
+ free( psz_key );
+ return faceid;
+}
+
+vlc_face_id_t * vlc_ftcache_GetActiveFaceInfo( vlc_ftcache_t *ftcache,
+ vlc_ftcache_metrics_t *metrics )
+{
+ if( metrics )
+ {
+ metrics->width_px = ftcache->scaler.width;
+ metrics->height_px = ftcache->scaler.height;
+ }
+ return (vlc_face_id_t *) ftcache->scaler.face_id;
+}
+
+static int vlc_ftcache_SetCharmap( vlc_face_id_t *faceid, FT_Face p_face )
+{
+ if( FT_Select_Charmap( p_face, FT_ENCODING_UNICODE ) )
+ /* We've loaded a font face which is unhelpful for actually rendering text */
+ return VLC_EGENERIC;
+
+ faceid->charmap_index =
+ p_face->charmap ? FT_Get_Charmap_Index( p_face->charmap ) : 0;
+
+ return VLC_SUCCESS;
+}
+
+FT_Face vlc_ftcache_LoadFaceByID( vlc_ftcache_t *ftcache, vlc_face_id_t *faceid,
+ const vlc_ftcache_metrics_t *metrics )
+{
+ ftcache->scaler.face_id = faceid;
+ ftcache->scaler.width = metrics->width_px;
+ ftcache->scaler.height = metrics->height_px;
+
+ FT_Size size;
+ if(FTC_Manager_LookupSize( ftcache->cachemanager, &ftcache->scaler, &size ))
+ {
+ ftcache->scaler.face_id = NULL;
+ ftcache->scaler.width = 0;
+ ftcache->scaler.height = 0;
+ return NULL;
+ }
+
+ return size->face;
+}
+
+int vlc_ftcache_LoadFaceByIDNoSize( vlc_ftcache_t *ftcache, vlc_face_id_t *faceid )
+{
+ FT_Face face;
+ if( FTC_Manager_LookupFace( ftcache->cachemanager, faceid, &face ) )
+ return VLC_EGENERIC;
+
+ ftcache->style_flags = face->style_flags;
+ ftcache->scaler.face_id = faceid;
+ ftcache->scaler.width = 0;
+ ftcache->scaler.height = 0;
+ return VLC_SUCCESS;
+}
+
+FT_UInt vlc_ftcache_LookupCMapIndex( vlc_ftcache_t *ftcache, vlc_face_id_t *faceid, FT_UInt codepoint )
+{
+ return FTC_CMapCache_Lookup( ftcache->charmap_cache, faceid,
+ faceid->charmap_index, codepoint );
+}
+
+int vlc_ftcache_GetGlyphForCurrentFace( vlc_ftcache_t *ftcache, FT_UInt index,
+ vlc_ftcache_glyph_t *glyph, FT_Long *styleflags )
+{
+ int ret = FTC_ImageCache_LookupScaler( ftcache->image_cache,
+ &ftcache->scaler,
+ FT_LOAD_NO_BITMAP | FT_LOAD_DEFAULT,
+ index, &glyph->p_glyph, &glyph->ref );
+ if( !ret && styleflags )
+ *styleflags = ftcache->style_flags;
+ return ret;
+}
+
+static FT_Error RequestFace( FTC_FaceID face_id, FT_Library library,
+ FT_Pointer req_data, FT_Face* aface )
+{
+ vlc_ftcache_t *ftcache = (vlc_ftcache_t *) req_data;
+ vlc_face_id_t *faceid = (vlc_face_id_t *) face_id;
+ VLC_UNUSED(library);
+
+ *aface = doLoadFace( ftcache->obj, faceid->psz_filename, faceid->idx);
+
+ if( !*aface || vlc_ftcache_SetCharmap( faceid, *aface ) )
+ return -1;
+
+ return 0;
+}
+
+static void FreeFaceID( void *p_faceid, void *p_obj )
+{
+ VLC_UNUSED(p_obj);
+ vlc_face_id_t *faceid = p_faceid;
+ free(faceid->psz_filename);
+ free(faceid);
+}
+
+void vlc_ftcache_Delete( vlc_ftcache_t *ftcache )
+{
+ if( ftcache->cachemanager )
+ FTC_Manager_Done( ftcache->cachemanager );
+
+ /* Fonts dicts */
+ vlc_dictionary_clear( &ftcache->face_ids, FreeFaceID, NULL );
+
+ free( ftcache );
+}
+
+vlc_ftcache_t * vlc_ftcache_New( vlc_object_t *obj, FT_Library p_library,
+ unsigned maxkb )
+{
+ vlc_ftcache_t *ftcache = calloc(1, sizeof(*ftcache));
+ if(!ftcache)
+ return NULL;
+ ftcache->obj = obj;
+
+ /* Dictionnaries for fonts */
+ vlc_dictionary_init( &ftcache->face_ids, 50 );
+
+ if(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 ))
+ {
+ vlc_ftcache_Delete( ftcache );
+ return NULL;
+ }
+
+ ftcache->scaler.pixel = 1;
+ ftcache->scaler.x_res = 0;
+ ftcache->scaler.y_res = 0;
+
+ return ftcache;
+}
+
+void vlc_ftcache_Glyph_Release( vlc_ftcache_t *ftcache, vlc_ftcache_glyph_t *g )
+{
+ if( g->ref )
+ {
+ FTC_Node_Unref( g->ref, ftcache->cachemanager );
+ g->ref = NULL;
+ g->p_glyph = NULL;
+ }
+ else if( g->p_glyph ) /* glyph is not cache reference */
+ {
+ FT_Done_Glyph( g->p_glyph );
+ g->p_glyph = NULL;
+ }
+}
+
+void vlc_ftcache_Glyph_Init( vlc_ftcache_glyph_t *g )
+{
+ g->p_glyph = NULL;
+ g->ref = NULL;
+}
diff --git a/modules/text_renderer/freetype/ftcache.h b/modules/text_renderer/freetype/ftcache.h
new file mode 100644
index 0000000000..cb6d12d740
--- /dev/null
+++ b/modules/text_renderer/freetype/ftcache.h
@@ -0,0 +1,74 @@
+/*****************************************************************************
+ * ftcache.h : Font Face and glyph cache freetype2
+ *****************************************************************************
+ * Copyright (C) 2020 - VideoLabs, VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifndef FTCACHE_H
+#define FTCACHE_H
+
+#include FT_CACHE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct vlc_ftcache_t vlc_ftcache_t;
+
+typedef struct
+{
+ char *psz_filename;
+ unsigned idx;
+ unsigned int charmap_index;
+
+} vlc_face_id_t;
+
+vlc_ftcache_t * vlc_ftcache_New( vlc_object_t *, FT_Library, unsigned );
+void vlc_ftcache_Delete( vlc_ftcache_t * );
+
+/* Glyphs managed by the cache. Always use vlc_ftcache_Init/Release */
+typedef struct
+{
+ FT_Glyph p_glyph;
+ FTC_Node ref;
+} vlc_ftcache_glyph_t;
+
+void vlc_ftcache_Glyph_Init( vlc_ftcache_glyph_t * );
+void vlc_ftcache_Glyph_Release( vlc_ftcache_t *, vlc_ftcache_glyph_t * );
+
+vlc_face_id_t * vlc_ftcache_GetFaceID( vlc_ftcache_t *, const char *psz_fontfile, int i_idx );
+
+typedef struct
+{
+ int width_px;
+ int height_px;
+} vlc_ftcache_metrics_t;
+
+vlc_face_id_t * vlc_ftcache_GetActiveFaceInfo( vlc_ftcache_t *, vlc_ftcache_metrics_t * );
+int vlc_ftcache_GetGlyphForCurrentFace( vlc_ftcache_t *, FT_UInt charmap_index,
+ vlc_ftcache_glyph_t *, FT_Long * );
+FT_UInt vlc_ftcache_LookupCMapIndex( vlc_ftcache_t *, vlc_face_id_t *faceid, FT_UInt codepoint );
+/* Big fat warning : Do not store FT_Face.
+ * Faces are fully managed by cache and possibly invalidated when changing face */
+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 );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/modules/text_renderer/freetype/platform_fonts.c b/modules/text_renderer/freetype/platform_fonts.c
index 084b011e23..dfe50df108 100644
--- a/modules/text_renderer/freetype/platform_fonts.c
+++ b/modules/text_renderer/freetype/platform_fonts.c
@@ -49,27 +49,12 @@
#include "freetype.h"
#include "fonts/backends.h"
-static FT_Face LoadFace( filter_t *p_filter, const char *psz_fontfile, int i_idx,
- const text_style_t *p_style )
+FT_Face doLoadFace( void *ctx, const char *psz_fontfile, int i_idx )
{
+ filter_t *p_filter = ctx;
filter_sys_t *p_sys = p_filter->p_sys;
- char *psz_key = NULL;
-
- int i_font_size = ConvertToLiveSize( p_filter, p_style );
- int i_font_width = i_font_size;
- if( p_style->i_style_flags & STYLE_HALFWIDTH )
- i_font_width /= 2;
- else if( p_style->i_style_flags & STYLE_DOUBLEWIDTH )
- i_font_width *= 2;
-
- if( asprintf( &psz_key, "%s - %d - %d - %d",
- psz_fontfile, i_idx,
- i_font_size, i_font_width ) < 0 )
- return NULL;
- FT_Face p_face = vlc_dictionary_value_for_key( &p_sys->face_map, psz_key );
- if( p_face != NULL )
- goto done;
+ FT_Face p_face = NULL;
if( psz_fontfile[0] == ':' && psz_fontfile[1] == '/' )
{
@@ -81,76 +66,48 @@ static FT_Face LoadFace( filter_t *p_filter, const char *psz_fontfile, int i_idx
input_attachment_t *p_attach = p_sys->pp_font_attachments[ i_attach ];
if( FT_New_Memory_Face( p_sys->p_library, p_attach->p_data,
p_attach->i_data, i_idx, &p_face ) )
- msg_Err( p_filter, "LoadFace: Error creating face for %s", psz_key );
+ return NULL;
}
}
-
#if defined( _WIN32 )
else if( !memcmp( psz_fontfile, ":dw/", 4 ) )
{
int i_index = atoi( psz_fontfile + 4 );
- FT_Stream p_stream;
- if( DWrite_GetFontStream( p_sys->fs, i_index, &p_stream ) != VLC_SUCCESS )
- msg_Err( p_filter, "LoadFace: Invalid font stream index" );
- else
+ FT_Open_Args args = {0};
+ args.flags = FT_OPEN_STREAM;
+ if( DWrite_GetFontStream( p_sys->fs, i_index, &args.stream ) != VLC_SUCCESS ||
+ FT_Open_Face( p_sys->p_library, &args, i_idx, &p_face ) )
{
- FT_Open_Args args = {0};
- args.flags = FT_OPEN_STREAM;
- args.stream = p_stream;
- if( FT_Open_Face( p_sys->p_library, &args, i_idx, &p_face ) )
- msg_Err( p_filter, "LoadFace: Error creating face for %s", psz_key );
+ msg_Err( p_filter, "LoadFace: Invalid font stream index" );
+ return NULL;
}
}
#endif
else
if( FT_New_Face( p_sys->p_library, psz_fontfile, i_idx, &p_face ) )
- msg_Err( p_filter, "LoadFace: Error creating face for %s", psz_key );
-
- if( !p_face )
- goto done;
-
- if( FT_Select_Charmap( p_face, ft_encoding_unicode ) )
- {
- /* We've loaded a font face which is unhelpful for actually
- * rendering text - fallback to the default one.
- */
- msg_Err( p_filter, "LoadFace: Error selecting charmap for %s", psz_key );
- FT_Done_Face( p_face );
- p_face = NULL;
- goto done;
- }
-
- if( FT_Set_Pixel_Sizes( p_face, i_font_width, i_font_size ) )
- {
- msg_Err( p_filter,
- "LoadFace: Failed to set font size for %s", psz_key );
- FT_Done_Face( p_face );
- p_face = NULL;
- goto done;
- }
-
- vlc_dictionary_insert( &p_sys->face_map, psz_key, p_face );
+ return NULL;
-done:
- free( psz_key );
return p_face;
}
-FT_Face GetFace( vlc_font_select_t *fs, vlc_font_t *p_font, uni_char_t codepoint )
+bool CheckFace( vlc_font_select_t *fs, vlc_font_t *p_font, uni_char_t codepoint )
{
filter_sys_t *p_sys = fs->p_filter->p_sys;
- if( !p_font->p_face )
- p_font->p_face = LoadFace( fs->p_filter, p_font->psz_fontfile,
- p_font->i_index,
- p_sys->p_default_style );
+ vlc_face_id_t *faceid = p_font->faceid;
+ if( !faceid )
+ {
+ faceid = vlc_ftcache_GetFaceID( p_sys->ftcache,
+ p_font->psz_fontfile,
+ p_font->i_index );
+ p_font->faceid = faceid;
+ }
+
+ if( !faceid || vlc_ftcache_LoadFaceByIDNoSize( p_sys->ftcache, faceid ) )
+ return false;
- if( p_font->p_face &&
- FT_Get_Char_Index( p_font->p_face, codepoint ) )
- return p_font->p_face;
- else
- return NULL;
+ return vlc_ftcache_LookupCMapIndex( p_sys->ftcache, faceid, codepoint );
}
/**
@@ -173,7 +130,7 @@ static vlc_font_t *GetBestFont( vlc_font_select_t *fs, const vlc_family_t *p_fam
{
int i_score = 0;
- if( codepoint && GetFace( fs, p_font, codepoint ) )
+ if( codepoint && CheckFace( fs, p_font, codepoint ) )
i_score += 1000;
if( !!p_font->b_bold == !!b_bold )
@@ -207,7 +164,7 @@ vlc_family_t *SearchFallbacks( vlc_font_select_t *fs, vlc_family_t *p_fallbacks,
p_fallback->p_fonts = p_temp->p_fonts;
}
- if( !GetFace( fs, p_fallback->p_fonts, codepoint ) )
+ if( !CheckFace( fs, p_fallback->p_fonts, codepoint ) )
continue;
p_family = p_fallback;
@@ -226,7 +183,7 @@ static vlc_family_t *SearchFontByFamilyName( vlc_font_select_t *fs,
{
if( !strcasecmp( p->psz_name, psz_familyname ) &&
p->p_fonts &&
- GetFace( fs, p->p_fonts, codepoint ) )
+ CheckFace( fs, p->p_fonts, codepoint ) )
return p;
}
return NULL;
@@ -603,7 +560,7 @@ static char* SelectFontWithFamilyFallback( vlc_font_select_t *fs,
const bool b_italic = p_style->i_style_flags & STYLE_ITALIC;
const vlc_family_t *p_family = NULL;
- if( codepoint )
+ if( codepoint && !p_family )
{
vlc_family_t *p_fallbacks;
const char *psz_name;
@@ -628,7 +585,7 @@ static char* SelectFontWithFamilyFallback( vlc_font_select_t *fs,
p_family = FontSelectGetFamily( fs, psz_name );
if( p_family && p_family->p_fonts )
{
- if( GetFace( fs, p_family->p_fonts, codepoint ) )
+ if( CheckFace( fs, p_family->p_fonts, codepoint ) )
{
Debug( fs->p_obj, "Found family \"%s\" for codepoint %x",
psz_name, codepoint );
@@ -642,7 +599,7 @@ static char* SelectFontWithFamilyFallback( vlc_font_select_t *fs,
/* Try font attachments if not available locally */
if( !p_family )
{
- Debug( fs->p_obj, "Looking for family \"%s\" in attachments", psz_name );
+ Debug( fs->p_obj, "Looking for family \"%s\" in attachments cp %x", psz_name, codepoint );
p_fallbacks = vlc_dictionary_value_for_key( &fs->fallback_map,
FB_LIST_ATTACHMENTS );
if( p_fallbacks )
@@ -661,7 +618,7 @@ static char* SelectFontWithFamilyFallback( vlc_font_select_t *fs,
{
vlc_vector_foreach( psz_name, families )
{
- Debug( fs->p_obj, "Looking for family \"%s\" in system fallbacks", psz_name );
+ Debug( fs->p_obj, "Looking for family \"%s\" in system fallbacks cp %x", psz_name, codepoint );
p_fallbacks = FontSelectGetFallbacks( fs, psz_name, codepoint );
if( p_fallbacks )
{
@@ -715,8 +672,8 @@ static char* SelectFontWithFamilyFallback( vlc_font_select_t *fs,
return NULL;
}
-FT_Face SelectAndLoadFace( filter_t *p_filter, const text_style_t *p_style,
- uni_char_t codepoint )
+vlc_face_id_t *
+SelectAndLoadFace( filter_t *p_filter, const text_style_t *p_style, uni_char_t codepoint )
{
filter_sys_t *p_sys = p_filter->p_sys;
const char *psz_fontname = (p_style->i_style_flags & STYLE_MONOSPACED)
@@ -731,17 +688,27 @@ FT_Face SelectAndLoadFace( filter_t *p_filter, const text_style_t *p_style,
return NULL;
}
- FT_Face p_face = NULL;
+ vlc_face_id_t *p_faceid = NULL;
int i_idx = 0;
char *psz_fontfile =
SelectFontWithFamilyFallback( p_sys->fs, &families, p_style,
&i_idx, codepoint );
+
if( psz_fontfile && *psz_fontfile != '\0' )
{
- p_face = LoadFace( p_filter, psz_fontfile, i_idx, p_style );
+ p_faceid = vlc_ftcache_GetFaceID( p_sys->ftcache, psz_fontfile, i_idx );
+ if( p_faceid )
+ {
+ vlc_ftcache_metrics_t metrics;
+ metrics.height_px = ConvertToLiveSize( p_filter, p_style );
+ metrics.width_px = GetFontWidthForStyle( p_style, metrics.height_px );
+ if( !vlc_ftcache_LoadFaceByID( p_sys->ftcache, p_faceid, &metrics ) )
+ p_faceid = NULL;
+ }
}
- else
+
+ if( !p_faceid )
{
msg_Warn( p_filter,
"SelectAndLoadFace: no font found for family: %s, codepoint: 0x%x",
@@ -753,7 +720,8 @@ FT_Face SelectAndLoadFace( filter_t *p_filter, const text_style_t *p_style,
free( psz_temp );
vlc_vector_clear( &families );
free( psz_fontfile );
- return p_face;
+
+ return p_faceid;
}
#ifndef HAVE_GET_FONT_BY_FAMILY_NAME
diff --git a/modules/text_renderer/freetype/platform_fonts.h b/modules/text_renderer/freetype/platform_fonts.h
index feb03078ba..a977a1b459 100644
--- a/modules/text_renderer/freetype/platform_fonts.h
+++ b/modules/text_renderer/freetype/platform_fonts.h
@@ -132,7 +132,7 @@ struct vlc_font_t
int i_index; /**< index of the font in the font file, starts at 0 */
bool b_bold; /**< if the font is a bold version */
bool b_italic; /**< if the font is an italic version */
- FT_Face p_face; /**< the freetype structure for the font */
+ void *faceid; /* fontloader ref to font */
};
/**
@@ -277,11 +277,11 @@ char* ToLower( const char *psz_src );
/* Size helper, depending on the scaling factor */
int ConvertToLiveSize( filter_t *p_filter, const text_style_t *p_style );
-
/* Only for fonts implementors */
vlc_family_t *SearchFallbacks( vlc_font_select_t *, vlc_family_t *p_fallbacks,
uni_char_t codepoint );
-FT_Face GetFace( vlc_font_select_t *, vlc_font_t *p_font, uni_char_t codepoint );
+bool CheckFace( vlc_font_select_t *fs, vlc_font_t *p_font, uni_char_t codepoint );
+FT_Face doLoadFace( void *, const char *psz_fontfile, int i_idx );
char * MakeFilePath( vlc_font_select_t *, const char *psz_filename );
diff --git a/modules/text_renderer/freetype/text_layout.c b/modules/text_renderer/freetype/text_layout.c
index 15ac84f041..127d53d151 100644
--- a/modules/text_renderer/freetype/text_layout.c
+++ b/modules/text_renderer/freetype/text_layout.c
@@ -101,7 +101,7 @@ typedef struct run_desc_t
{
int i_start_offset;
int i_end_offset;
- FT_Face p_face;
+ vlc_face_id_t *p_faceid;
const text_style_t *p_style;
#ifdef HAVE_HARFBUZZ
@@ -117,7 +117,7 @@ typedef struct run_desc_t
*/
typedef struct glyph_bitmaps_t
{
- FT_Glyph p_glyph;
+ vlc_ftcache_glyph_t cglyph;
FT_Glyph p_outline;
FT_Glyph p_shadow;
FT_BBox glyph_bbox;
@@ -134,8 +134,8 @@ typedef struct paragraph_t
uni_char_t *p_code_points; /**< Unicode code points */
int *pi_glyph_indices; /**< Glyph index values within the run's font face */
text_style_t **pp_styles;
- ruby_block_t **pp_ruby;
- FT_Face *pp_faces; /**< Used to determine run boundaries when performing font fallback */
+ ruby_block_t **pp_ruby;
+ vlc_face_id_t **pp_facesidx; /**< Used to determine run boundaries when performing font fallback */
int *pi_run_ids; /**< The run to which each glyph belongs */
glyph_bitmaps_t *p_glyph_bitmaps;
int i_size;
@@ -290,7 +290,7 @@ static void FreeParagraph( paragraph_t *p_paragraph )
free( p_paragraph->pi_glyph_indices );
free( p_paragraph->p_glyph_bitmaps );
free( p_paragraph->pi_run_ids );
- free( p_paragraph->pp_faces );
+ free( p_paragraph->pp_facesidx );
free( p_paragraph->pp_ruby );
free( p_paragraph->pp_styles );
free( p_paragraph->p_code_points );
@@ -329,8 +329,8 @@ static paragraph_t *NewParagraph( filter_t *p_filter,
vlc_alloc( i_size, sizeof( *p_paragraph->pi_glyph_indices ) );
p_paragraph->pp_styles =
vlc_alloc( i_size, sizeof( *p_paragraph->pp_styles ) );
- p_paragraph->pp_faces =
- calloc( i_size, sizeof( *p_paragraph->pp_faces ) );
+ p_paragraph->pp_facesidx =
+ calloc( i_size, sizeof( *p_paragraph->pp_facesidx ) );
p_paragraph->pi_run_ids =
calloc( i_size, sizeof( *p_paragraph->pi_run_ids ) );
p_paragraph->p_glyph_bitmaps =
@@ -343,7 +343,7 @@ static paragraph_t *NewParagraph( filter_t *p_filter,
p_paragraph->i_runs_count = 0;
if( !p_paragraph->p_code_points || !p_paragraph->pi_glyph_indices
- || !p_paragraph->pp_styles || !p_paragraph->pp_faces
+ || !p_paragraph->pp_styles || !p_paragraph->pp_facesidx
|| !p_paragraph->pi_run_ids|| !p_paragraph->p_glyph_bitmaps
|| !p_paragraph->p_runs )
goto error;
@@ -471,7 +471,7 @@ static int AddRun( filter_t *p_filter,
paragraph_t *p_paragraph,
int i_start_offset,
int i_end_offset,
- FT_Face p_face,
+ vlc_face_id_t *p_faceid,
const text_style_t *p_style )
{
if( i_start_offset >= i_end_offset
@@ -504,7 +504,7 @@ static int AddRun( filter_t *p_filter,
run_desc_t *p_run = p_paragraph->p_runs + p_paragraph->i_runs_count++;
p_run->i_start_offset = i_start_offset;
p_run->i_end_offset = i_end_offset;
- p_run->p_face = p_face;
+ p_run->p_faceid = p_faceid;
if( p_style )
p_run->p_style = p_style;
@@ -530,6 +530,8 @@ static int AddRun( filter_t *p_filter,
static int AddRunWithFallback( filter_t *p_filter, paragraph_t *p_paragraph,
int i_start_offset, int i_end_offset )
{
+ filter_sys_t *p_sys = p_filter->p_sys;
+
if( i_start_offset >= i_end_offset
|| i_start_offset < 0 || i_start_offset >= p_paragraph->i_size
|| i_end_offset <= 0 || i_end_offset > p_paragraph->i_size )
@@ -545,8 +547,8 @@ static int AddRunWithFallback( filter_t *p_filter, paragraph_t *p_paragraph,
/* Maximum number of faces to try for each run */
#define MAX_FACES 5
- FT_Face pp_faces[ MAX_FACES ] = {0};
- FT_Face p_face = NULL;
+ vlc_face_id_t *pp_facesidx[ MAX_FACES ] = {0};
+ vlc_face_id_t *p_faceidx = NULL;
for( int i = i_start_offset; i < i_end_offset; ++i )
{
@@ -558,33 +560,32 @@ static int AddRunWithFallback( filter_t *p_filter, paragraph_t *p_paragraph,
* For white space, punctuation and neutral characters, try to use
* the font of the previous character, if any. See #20466.
*/
- if( p_face &&
+ if( p_faceidx &&
( p_paragraph->p_types[ i ] == FRIBIDI_TYPE_WS
|| p_paragraph->p_types[ i ] == FRIBIDI_TYPE_CS
|| p_paragraph->p_types[ i ] == FRIBIDI_TYPE_ON ) )
{
- i_glyph_index = FT_Get_Char_Index( p_face,
- p_paragraph->p_code_points[ i ] );
+ i_glyph_index = vlc_ftcache_LookupCMapIndex( p_sys->ftcache, p_faceidx,
+ p_paragraph->p_code_points[ i ] );
if( i_glyph_index )
{
- p_paragraph->pp_faces[ i ] = p_face;
+ p_paragraph->pp_facesidx[ i ] = p_faceidx;
continue;
}
}
#endif
do {
- p_face = pp_faces[ i_index ];
- if( !p_face )
- p_face = pp_faces[ i_index ] =
- SelectAndLoadFace( p_filter, p_style,
- p_paragraph->p_code_points[ i ] );
- if( !p_face )
+ p_faceidx = pp_facesidx[ i_index ];
+ if( !p_faceidx )
+ p_faceidx = pp_facesidx[ i_index ] =
+ SelectAndLoadFace( p_filter, p_style, p_paragraph->p_code_points[ i ] );
+ if( !p_faceidx )
continue;
- i_glyph_index = FT_Get_Char_Index( p_face,
- p_paragraph->p_code_points[ i ] );
+ i_glyph_index = vlc_ftcache_LookupCMapIndex( p_sys->ftcache, p_faceidx,
+ p_paragraph->p_code_points[ i ] );
if( i_glyph_index )
- p_paragraph->pp_faces[ i ] = p_face;
+ p_paragraph->pp_facesidx[ i ] = p_faceidx;
} while( i_glyph_index == 0 && ++i_index < MAX_FACES );
}
@@ -593,11 +594,11 @@ static int AddRunWithFallback( filter_t *p_filter, paragraph_t *p_paragraph,
for( int i = i_start_offset; i <= i_end_offset; ++i )
{
if( i == i_end_offset
- || p_paragraph->pp_faces[ i_run_start ] != p_paragraph->pp_faces[ i ] )
+ || p_paragraph->pp_facesidx[ i_run_start ] != p_paragraph->pp_facesidx[ i ] )
{
- if( p_paragraph->pp_faces[ i_run_start ] &&
+ if( p_paragraph->pp_facesidx[ i_run_start ] &&
AddRun( p_filter, p_paragraph, i_run_start, i,
- p_paragraph->pp_faces[ i_run_start ], NULL ) )
+ p_paragraph->pp_facesidx[ i_run_start ], NULL ) )
return VLC_EGENERIC;
i_run_start = i;
@@ -707,7 +708,6 @@ static int ShapeParagraphHarfBuzz( filter_t *p_filter,
for( int i = 0; i < p_paragraph->i_runs_count; ++i )
{
run_desc_t *p_run = p_paragraph->p_runs + i;
- const text_style_t *p_style = p_run->p_style;
/*
* With HarfBuzz and no font fallback, this is where font faces
@@ -718,21 +718,30 @@ static int ShapeParagraphHarfBuzz( filter_t *p_filter,
* loaded in AddRunWithFallback(), except for runs of codepoints
* for which no font could be found.
*/
- FT_Face p_face = 0;
- if( !p_run->p_face )
+ if( !p_run->p_faceid )
{
- p_face = SelectAndLoadFace( p_filter, p_style,
- p_paragraph->p_code_points[p_run->i_start_offset] );
- if( !p_face )
+ p_run->p_faceid = SelectAndLoadFace( p_filter, p_run->p_style,
+ p_paragraph->p_code_points[p_run->i_start_offset] );
+ if( !p_run->p_faceid )
{
- p_face = p_sys->p_face;
- p_style = p_sys->p_default_style;
- p_run->p_style = p_style;
+ p_run->p_faceid = p_sys->p_faceid;
+ p_run->p_style = p_sys->p_default_style;
}
- p_run->p_face = p_face;
}
- else
- p_face = p_run->p_face;
+
+ vlc_face_id_t *p_faceid = p_run->p_faceid;
+ const text_style_t *p_style = p_run->p_style;
+
+ if(!p_faceid)
+ goto error;
+
+ vlc_ftcache_metrics_t metrics;
+ metrics.height_px = ConvertToLiveSize( p_filter, p_style );
+ metrics.width_px = GetFontWidthForStyle( p_style, metrics.height_px );
+
+ FT_Face p_face = vlc_ftcache_LoadFaceByID( p_sys->ftcache, p_faceid, &metrics );
+ if(!p_face)
+ goto error;
hb_font_t *p_hb_font = hb_ft_font_create( p_face, 0 );
if( !p_hb_font )
@@ -767,6 +776,7 @@ static int ShapeParagraphHarfBuzz( filter_t *p_filter,
hb_shape( p_hb_font, p_run->p_buffer, 0, 0 );
hb_font_destroy( p_hb_font );
+ p_hb_font = 0;
const unsigned length = hb_buffer_get_length( p_run->p_buffer );
if( length == 0 )
@@ -844,7 +854,7 @@ static int ShapeParagraphHarfBuzz( filter_t *p_filter,
++i_index;
}
if( AddRun( p_filter, p_new_paragraph, i_index - i_glyph_count,
- i_index, p_run->p_face, p_run->p_style ) )
+ i_index, p_run->p_faceid, p_run->p_style ) )
goto error;
}
@@ -916,8 +926,9 @@ static int ShapeParagraphFriBidi( filter_t *p_filter, paragraph_t *p_paragraph )
* inserted when shaping with FriBidi, when it performs glyph substitution for
* ligatures.
*/
-static int RemoveZeroWidthCharacters( paragraph_t *p_paragraph )
+static int RemoveZeroWidthCharacters( filter_t *p_filter, paragraph_t *p_paragraph )
{
+ filter_sys_t *p_sys = p_filter->p_sys;
for( int i = 0; i < p_paragraph->i_size; ++i )
{
uni_char_t ch = p_paragraph->p_code_points[ i ];
@@ -928,11 +939,9 @@ static int RemoveZeroWidthCharacters( paragraph_t *p_paragraph )
|| ( ch >= 0x200b && ch <= 0x200f ) )
{
glyph_bitmaps_t *p_bitmaps = p_paragraph->p_glyph_bitmaps + i;
- if( p_bitmaps->p_glyph )
- FT_Done_Glyph( p_bitmaps->p_glyph );
if( p_bitmaps->p_outline )
FT_Done_Glyph( p_bitmaps->p_outline );
- p_bitmaps->p_glyph = 0;
+ 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;
@@ -961,6 +970,18 @@ static int ZeroNsmAdvance( paragraph_t *p_paragraph )
#endif
#endif
+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 )
+ FT_Done_Glyph( p_bitmaps->p_shadow );
+ if( p_bitmaps->p_outline )
+ FT_Done_Glyph( p_bitmaps->p_outline );
+ vlc_ftcache_Glyph_Release( p_sys->ftcache, &p_bitmaps->cglyph );
+}
+
/**
* 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.
@@ -984,30 +1005,33 @@ static int LoadGlyphs( filter_t *p_filter, paragraph_t *p_paragraph,
{
run_desc_t *p_run = p_paragraph->p_runs + i;
const text_style_t *p_style = p_run->p_style;
- const int i_live_size = ConvertToLiveSize( p_filter, p_style );
+ vlc_ftcache_metrics_t metrics;
+
+ if( p_run->p_faceid )
+ {
+ metrics.height_px = ConvertToLiveSize( p_filter, p_style );
+ metrics.width_px = GetFontWidthForStyle( p_style, metrics.height_px );
+ if(! vlc_ftcache_LoadFaceByID( p_sys->ftcache, p_run->p_faceid, &metrics ) )
+ p_run->p_faceid = NULL;
+ }
- FT_Face p_face = 0;
- if( !p_run->p_face )
+ if( !p_run->p_faceid ) /* Fallback on default font and style */
{
- p_face = SelectAndLoadFace( p_filter, p_style,
- p_paragraph->p_code_points[p_run->i_start_offset] );
- if( !p_face )
+ metrics.height_px = ConvertToLiveSize( p_filter, p_sys->p_default_style );
+ metrics.width_px = GetFontWidthForStyle( p_sys->p_default_style, metrics.height_px );
+ if( vlc_ftcache_LoadFaceByID( p_sys->ftcache, p_sys->p_faceid, &metrics ) )
{
- /* Uses the default font and style */
- p_face = p_sys->p_face;
- p_style = p_sys->p_default_style;
- p_run->p_style = p_style;
+ p_run->p_faceid = p_sys->p_faceid;
+ p_run->p_style = p_style = p_sys->p_default_style;
}
- p_run->p_face = p_face;
+ else continue; /* can't do much from now */
}
- else
- p_face = p_run->p_face;
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 = ( i_live_size << 6 ) * f_outline_thickness;
+ int i_radius = ( metrics.height_px << 6 ) * f_outline_thickness;
FT_Stroker_Set( p_sys->p_stroker,
i_radius,
FT_STROKER_LINECAP_ROUND,
@@ -1020,14 +1044,16 @@ static int LoadGlyphs( filter_t *p_filter, paragraph_t *p_paragraph,
if( b_use_glyph_indices )
i_glyph_index = p_paragraph->pi_glyph_indices[ j ];
else
- i_glyph_index =
- FT_Get_Char_Index( p_face, p_paragraph->p_code_points[ j ] );
+ {
+ i_glyph_index = vlc_ftcache_LookupCMapIndex( p_sys->ftcache, p_run->p_faceid,
+ p_paragraph->p_code_points[ j ] );
+ }
glyph_bitmaps_t *p_bitmaps = p_paragraph->p_glyph_bitmaps + j;
#define SKIP_GLYPH( p_bitmaps ) \
{ \
- p_bitmaps->p_glyph = 0; \
+ vlc_ftcache_Glyph_Init( &p_bitmaps->cglyph );\
p_bitmaps->p_outline = 0; \
p_bitmaps->p_shadow = 0; \
p_bitmaps->i_x_advance = 0; \
@@ -1064,26 +1090,45 @@ static int LoadGlyphs( filter_t *p_filter, paragraph_t *p_paragraph,
SKIP_GLYPH( p_bitmaps )
}
- if( FT_Load_Glyph( p_face, i_glyph_index,
- FT_LOAD_NO_BITMAP | FT_LOAD_DEFAULT )
- && FT_Load_Glyph( p_face, i_glyph_index, FT_LOAD_DEFAULT ) )
- SKIP_GLYPH( p_bitmaps )
-
- if( ( p_style->i_style_flags & STYLE_BOLD )
- && !( p_face->style_flags & FT_STYLE_FLAG_BOLD ) )
- FT_GlyphSlot_Embolden( p_face->glyph );
- if( ( p_style->i_style_flags & STYLE_ITALIC )
- && !( p_face->style_flags & FT_STYLE_FLAG_ITALIC ) )
- FT_GlyphSlot_Oblique( p_face->glyph );
- if( FT_Get_Glyph( p_face->glyph, &p_bitmaps->p_glyph ) )
- SKIP_GLYPH( p_bitmaps )
+ FT_Long style_flags;
+ if( vlc_ftcache_GetGlyphForCurrentFace( p_sys->ftcache,
+ i_glyph_index,
+ &p_bitmaps->cglyph,
+ &style_flags ) )
+ SKIP_GLYPH( p_bitmaps );
#undef SKIP_GLYPH
+ const bool b_embolden = ( p_style->i_style_flags & STYLE_BOLD ) &&
+ !( style_flags & FT_STYLE_FLAG_BOLD );
+ const bool b_oblique = ( p_style->i_style_flags & STYLE_ITALIC ) &&
+ !( style_flags & FT_STYLE_FLAG_ITALIC );
+ /* Apply missing style by modifying the outline */
+ if( (b_embolden || b_oblique) &&
+ p_bitmaps->cglyph.p_glyph->format == FT_GLYPH_FORMAT_OUTLINE )
+ {
+ FT_Glyph transformed;
+ if( !FT_Glyph_Copy( p_bitmaps->cglyph.p_glyph, &transformed ) )
+ {
+ /* using a copy from now */
+ if( b_oblique )
+ {
+ FT_Matrix matrix = { .xx = 0x10000L, .xy = 0.12 * 0x10000L,
+ .yy = 0x10000L, .yx = 0 };
+ FT_Glyph_Transform( transformed, &matrix, 0 );
+ }
+ if( b_embolden )
+ FT_Outline_Embolden( &((FT_OutlineGlyph)transformed)->outline, 1<<6 );
+ vlc_ftcache_Glyph_Release( p_sys->ftcache, &p_bitmaps->cglyph );
+ p_bitmaps->cglyph.p_glyph = transformed;
+ }
+ }
+
+ /* !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->p_glyph;
+ 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;
@@ -1091,12 +1136,12 @@ static int LoadGlyphs( filter_t *p_filter, paragraph_t *p_paragraph,
if( p_style->i_shadow_alpha != STYLE_ALPHA_TRANSPARENT )
p_bitmaps->p_shadow = p_bitmaps->p_outline ?
- p_bitmaps->p_outline : p_bitmaps->p_glyph;
+ p_bitmaps->p_outline : p_bitmaps->cglyph.p_glyph;
if( b_overwrite_advance )
{
- p_bitmaps->i_x_advance = p_face->glyph->advance.x;
- p_bitmaps->i_y_advance = p_face->glyph->advance.y;
+ p_bitmaps->i_x_advance = p_bitmaps->cglyph.p_glyph->advance.x >> 10;
+ p_bitmaps->i_y_advance = p_bitmaps->cglyph.p_glyph->advance.y >> 10;
}
unsigned i_x_advance = FT_FLOOR( abs( p_bitmaps->i_x_advance ) );
@@ -1134,8 +1179,7 @@ static int LayoutLine( filter_t *p_filter,
FT_Face p_face = 0;
FT_Vector pen = { .x = 0, .y = 0 };
- int i_font_size = 0;
- int i_font_width = 0;
+ vlc_ftcache_metrics_t metrics = { 0 };
int i_font_max_advance_y = 0;
int i_ul_offset = 0;
int i_ul_thickness = 0;
@@ -1172,7 +1216,7 @@ static int LayoutLine( filter_t *p_filter,
glyph_bitmaps_t *p_bitmaps =
p_paragraph->p_glyph_bitmaps + i_paragraph_index;
- if( !p_bitmaps->p_glyph )
+ if( !p_bitmaps->cglyph.p_glyph )
{
BBoxInit( &p_ch->bbox );
continue;
@@ -1183,13 +1227,11 @@ static int LayoutLine( filter_t *p_filter,
i_last_run = p_paragraph->pi_run_ids[ i_paragraph_index ];
p_run = p_paragraph->p_runs + i_last_run;
p_style = p_run->p_style;
- p_face = p_run->p_face;
- i_font_width = i_font_size = ConvertToLiveSize( p_filter, p_style );
- if( p_style->i_style_flags & STYLE_HALFWIDTH )
- i_font_width /= 2;
- else if( p_style->i_style_flags & STYLE_DOUBLEWIDTH )
- i_font_width *= 2;
+ metrics.height_px = ConvertToLiveSize( p_filter, p_style );
+ metrics.width_px = GetFontWidthForStyle( p_style, metrics.height_px );
+
+ p_face = vlc_ftcache_LoadFaceByID( p_sys->ftcache, p_run->p_faceid, &metrics );
}
FT_Vector pen_new = {
@@ -1197,59 +1239,61 @@ static int LayoutLine( filter_t *p_filter,
.y = pen.y + p_paragraph->p_glyph_bitmaps[ i_paragraph_index ].i_y_offset
};
FT_Vector pen_shadow = {
- .x = pen_new.x + p_sys->f_shadow_vector_x * ( i_font_width << 6 ),
- .y = pen_new.y + p_sys->f_shadow_vector_y * ( i_font_size << 6 )
+ .x = pen_new.x + p_sys->f_shadow_vector_x * ( metrics.width_px << 6 ),
+ .y = pen_new.y + p_sys->f_shadow_vector_y * ( metrics.height_px << 6 )
};
- if( p_bitmaps->p_shadow )
+ /* Shadow being a reference to main glyph, it must be processed first */
+ if( p_bitmaps->p_shadow &&
+ FT_Glyph_To_Bitmap( &p_bitmaps->p_shadow, FT_RENDER_MODE_NORMAL,
+ &pen_shadow, 0 ) )
{
- if( FT_Glyph_To_Bitmap( &p_bitmaps->p_shadow, FT_RENDER_MODE_NORMAL,
- &pen_shadow, 0 ) )
- p_bitmaps->p_shadow = 0;
- else
- FT_Glyph_Get_CBox( p_bitmaps->p_shadow, FT_GLYPH_BBOX_PIXELS,
- &p_bitmaps->shadow_bbox );
+ p_bitmaps->p_shadow = 0;
}
- if( p_bitmaps->p_glyph )
+
+ /* Ensure we don't release reference */
+ FT_Glyph bitmapglyph = p_bitmaps->cglyph.p_glyph;
+ if( FT_Glyph_To_Bitmap( &bitmapglyph,
+ FT_RENDER_MODE_NORMAL,
+ &pen_new, 0 ) )
{
- if( FT_Glyph_To_Bitmap( &p_bitmaps->p_glyph, FT_RENDER_MODE_NORMAL,
- &pen_new, 1 ) )
- {
- FT_Done_Glyph( p_bitmaps->p_glyph );
- if( p_bitmaps->p_outline )
- FT_Done_Glyph( p_bitmaps->p_outline );
- if( p_bitmaps->p_shadow != p_bitmaps->p_glyph )
- FT_Done_Glyph( p_bitmaps->p_shadow );
- continue;
- }
- else
- FT_Glyph_Get_CBox( p_bitmaps->p_glyph, FT_GLYPH_BBOX_PIXELS,
- &p_bitmaps->glyph_bbox );
+ ReleaseGlyphBitMaps( p_filter, p_bitmaps );
+ continue;
}
- if( p_bitmaps->p_outline )
+
+ /* release the source glyph or reference */
+ 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( FT_Glyph_To_Bitmap( &p_bitmaps->p_outline, FT_RENDER_MODE_NORMAL,
- &pen_new, 1 ) )
- {
- FT_Done_Glyph( p_bitmaps->p_outline );
- p_bitmaps->p_outline = 0;
- }
- else
- FT_Glyph_Get_CBox( p_bitmaps->p_outline, FT_GLYPH_BBOX_PIXELS,
- &p_bitmaps->outline_bbox );
+ FT_Done_Glyph( p_bitmaps->p_outline );
+ p_bitmaps->p_outline = 0;
}
- FixGlyph( p_bitmaps->p_glyph, &p_bitmaps->glyph_bbox,
+ FT_Glyph_Get_CBox( p_bitmaps->cglyph.p_glyph, FT_GLYPH_BBOX_PIXELS,
+ &p_bitmaps->glyph_bbox );
+ 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 )
+ {
+ FT_Glyph_Get_CBox( p_bitmaps->p_outline, FT_GLYPH_BBOX_PIXELS,
+ &p_bitmaps->outline_bbox );
FixGlyph( p_bitmaps->p_outline, &p_bitmaps->outline_bbox,
p_bitmaps->i_x_advance, p_bitmaps->i_y_advance,
&pen_new );
+ }
if( p_bitmaps->p_shadow )
+ {
+ FT_Glyph_Get_CBox( p_bitmaps->p_shadow, FT_GLYPH_BBOX_PIXELS,
+ &p_bitmaps->shadow_bbox );
FixGlyph( p_bitmaps->p_shadow, &p_bitmaps->shadow_bbox,
p_bitmaps->i_x_advance, p_bitmaps->i_y_advance,
&pen_shadow );
+ }
int i_line_offset = 0;
int i_line_thickness = 0;
@@ -1293,7 +1337,7 @@ static int LayoutLine( filter_t *p_filter,
}
}
- p_ch->p_glyph = ( FT_BitmapGlyph ) p_bitmaps->p_glyph;
+ p_ch->p_glyph = ( FT_BitmapGlyph ) p_bitmaps->cglyph.p_glyph;
p_ch->p_outline = ( FT_BitmapGlyph ) p_bitmaps->p_outline;
p_ch->p_shadow = ( FT_BitmapGlyph ) p_bitmaps->p_shadow;
@@ -1392,14 +1436,6 @@ static int LayoutLine( filter_t *p_filter,
return VLC_SUCCESS;
}
-static inline void ReleaseGlyphBitMaps(glyph_bitmaps_t *p_bitmaps)
-{
- if( p_bitmaps->p_glyph )
- FT_Done_Glyph( p_bitmaps->p_glyph );
- if( p_bitmaps->p_outline )
- FT_Done_Glyph( p_bitmaps->p_outline );
-}
-
static inline bool IsWhitespaceAt( paragraph_t *p_paragraph, size_t i )
{
return ( p_paragraph->p_code_points[ i ] == ' '
@@ -1456,7 +1492,7 @@ static int LayoutParagraph( filter_t *p_filter, paragraph_t *p_paragraph,
if( i_total_width == 0 )
{
for( int i=0; i < p_paragraph->i_size; ++i )
- ReleaseGlyphBitMaps( &p_paragraph->p_glyph_bitmaps[ i ] );
+ ReleaseGlyphBitMaps( p_filter, &p_paragraph->p_glyph_bitmaps[ i ] );
return VLC_SUCCESS;
}
@@ -1503,7 +1539,7 @@ static int LayoutParagraph( filter_t *p_filter, paragraph_t *p_paragraph,
* At this point p_shadow points to either p_glyph or p_outline,
* so we should not free it explicitly.
*/
- ReleaseGlyphBitMaps( &p_paragraph->p_glyph_bitmaps[ i ] );
+ ReleaseGlyphBitMaps( p_filter, &p_paragraph->p_glyph_bitmaps[ i ] );
i_line_start = i + 1;
continue;
}
@@ -1531,7 +1567,7 @@ static int LayoutParagraph( filter_t *p_filter, paragraph_t *p_paragraph,
* Not wrapping, that can't be rendered anymore. */
msg_Dbg( p_filter, "LayoutParagraph(): First glyph width in line exceeds maximum, skipping" );
for( ; i < p_paragraph->i_size; ++i )
- ReleaseGlyphBitMaps( &p_paragraph->p_glyph_bitmaps[ i ] );
+ ReleaseGlyphBitMaps( p_filter, &p_paragraph->p_glyph_bitmaps[ i ] );
return VLC_SUCCESS;
}
@@ -1550,7 +1586,7 @@ static int LayoutParagraph( filter_t *p_filter, paragraph_t *p_paragraph,
if( p_run->p_style->e_wrapinfo == STYLE_WRAP_NONE )
{
for( ; i < p_paragraph->i_size; ++i )
- ReleaseGlyphBitMaps( &p_paragraph->p_glyph_bitmaps[ i ] );
+ ReleaseGlyphBitMaps( p_filter, &p_paragraph->p_glyph_bitmaps[ i ] );
break;
}
@@ -1564,7 +1600,7 @@ static int LayoutParagraph( filter_t *p_filter, paragraph_t *p_paragraph,
if( i_newline_start + 1 < p_paragraph->i_size )
{
i_line_start = i_newline_start + 1;
- ReleaseGlyphBitMaps( &p_paragraph->p_glyph_bitmaps[ i_newline_start ] );
+ ReleaseGlyphBitMaps( p_filter, &p_paragraph->p_glyph_bitmaps[ i_newline_start ] );
}
else
i_line_start = i_newline_start; // == i
@@ -1584,7 +1620,7 @@ static int LayoutParagraph( filter_t *p_filter, paragraph_t *p_paragraph,
error:
for( int i = i_line_start; i < p_paragraph->i_size; ++i )
- ReleaseGlyphBitMaps( &p_paragraph->p_glyph_bitmaps[ i ] );
+ ReleaseGlyphBitMaps( p_filter, &p_paragraph->p_glyph_bitmaps[ i ] );
if( p_first_line )
FreeLines( p_first_line );
return VLC_EGENERIC;
@@ -1626,7 +1662,7 @@ static paragraph_t * BuildParagraph( filter_t *p_filter,
goto error;
if( LoadGlyphs( p_filter, p_paragraph, false, true, pi_max_advance_x ) )
goto error;
- if( RemoveZeroWidthCharacters( p_paragraph ) )
+ if( RemoveZeroWidthCharacters( p_filter, p_paragraph ) )
goto error;
if( ZeroNsmAdvance( p_paragraph ) )
goto error;
More information about the vlc-commits
mailing list