From 9fdb13fd53214359318f63942d00001d18ce3124 Mon Sep 17 00:00:00 2001 From: eugeni Date: Tue, 28 Nov 2006 22:50:02 +0000 Subject: If a glyph is not found in the current font, switch to another one. git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@21367 b3059339-0415-0410-9bf9-f77b7e298cf2 --- help/help_mp-en.h | 3 +++ libass/ass_font.c | 55 +++++++++++++++++++++++++++++++++++++++++ libass/ass_font.h | 7 ++++++ libass/ass_fontconfig.c | 65 ++++++++++++++++++++++++++++++++++++++----------- libass/ass_fontconfig.h | 8 ++++++ 5 files changed, 124 insertions(+), 14 deletions(-) diff --git a/help/help_mp-en.h b/help/help_mp-en.h index 4c1eccd219..90c1522532 100644 --- a/help/help_mp-en.h +++ b/help/help_mp-en.h @@ -2041,3 +2041,6 @@ static char help_text[]= #define MSGTR_LIBASS_EventHeightHasChanged "[ass] Warning! Event height has changed! \n" #define MSGTR_LIBASS_TooManySimultaneousEvents "[ass] Too many simultaneous events!\n" +// ass_font.c +#define MSGTR_LIBASS_GlyphNotFoundReselectingFont "[ass] Glyph 0x%X not found, reselecting font for (%s, %d, %d)\n" +#define MSGTR_LIBASS_GlyphNotFound "[ass] Glyph 0x%X not found in font for (%s, %d, %d)\n" diff --git a/libass/ass_font.c b/libass/ass_font.c index 3120db04f2..2a44c9fc2c 100644 --- a/libass/ass_font.c +++ b/libass/ass_font.c @@ -86,6 +86,10 @@ ass_font_t* ass_font_new(FT_Library ftlibrary, void* fc_priv, ass_font_desc_t* d font->v.x = font->v.y = 0; font->size = 0; +#ifdef HAVE_FONTCONFIG + font->charset = FcCharSetCreate(); +#endif + ass_font_cache_add(font); return font; @@ -118,6 +122,40 @@ void ass_font_set_size(ass_font_t* font, int size) } } +#ifdef HAVE_FONTCONFIG +static void ass_font_reselect(void* fontconfig_priv, ass_font_t* font) +{ + char* path; + int index; + FT_Face face; + int error; + + path = fontconfig_select_with_charset(fontconfig_priv, font->desc.family, font->desc.bold, + font->desc.italic, &index, font->charset); + if (strcasecmp(path, font->path) == 0 && index == font->index) { + free(path); + return; + } + + error = FT_New_Face(font->ftlibrary, path, index, &face); + if (error) { + mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorOpeningFont, path, index); + return; + } + charmap_magic(face); + + if (font->face) FT_Done_Face(font->face); + free(font->path); + + font->face = face; + font->path = strdup(path); + font->index = index; + + FT_Set_Transform(font->face, &font->m, &font->v); + FT_Set_Pixel_Sizes(font->face, 0, font->size); +} +#endif + FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch) { int error; @@ -128,6 +166,20 @@ FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch return 0; index = FT_Get_Char_Index(font->face, ch); +#ifdef HAVE_FONTCONFIG + FcCharSetAddChar(font->charset, ch); + if (index == 0) { + mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_GlyphNotFoundReselectingFont, + ch, font->desc.family, font->desc.bold, font->desc.italic); + ass_font_reselect(fontconfig_priv, font); + index = FT_Get_Char_Index(font->face, ch); + if (index == 0) { + mp_msg(MSGT_ASS, MSGL_ERR, MSGTR_LIBASS_GlyphNotFound, + ch, font->desc.family, font->desc.bold, font->desc.italic); + } + } +#endif + error = FT_Load_Glyph(font->face, index, FT_LOAD_NO_BITMAP ); if (error) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph); @@ -157,5 +209,8 @@ void ass_font_free(ass_font_t* font) if (font->face) FT_Done_Face(font->face); if (font->path) free(font->path); if (font->desc.family) free(font->desc.family); +#ifdef HAVE_FONTCONFIG + if (font->charset) FcCharSetDestroy(font->charset); +#endif free(font); } diff --git a/libass/ass_font.h b/libass/ass_font.h index f1ae7a6e16..aac42e9a24 100644 --- a/libass/ass_font.h +++ b/libass/ass_font.h @@ -21,6 +21,10 @@ #ifndef __ASS_FONT_H__ #define __ASS_FONT_H__ +#ifdef HAVE_FONTCONFIG +#include +#endif + typedef struct ass_font_desc_s { char* family; unsigned bold; @@ -36,6 +40,9 @@ typedef struct ass_font_s { FT_Matrix m; // current transformation FT_Vector v; // current shift int size; +#ifdef HAVE_FONTCONFIG + FcCharSet* charset; +#endif } ass_font_t; ass_font_t* ass_font_new(FT_Library ftlibrary, void* fc_priv, ass_font_desc_t* desc); diff --git a/libass/ass_fontconfig.c b/libass/ass_fontconfig.c index b4ac44e863..8cb6db205e 100644 --- a/libass/ass_fontconfig.c +++ b/libass/ass_fontconfig.c @@ -53,7 +53,8 @@ struct fc_instance_s { * \param index out: font index inside a file * \return font file path */ -static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index) +static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index, + FcCharSet* charset) { FcBool rc; FcResult result; @@ -61,6 +62,9 @@ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold int val_i; FcChar8* val_s; FcBool val_b; + FcCharSet* val_cs; + FcFontSet* fset; + int curf, bestf, bestdiff = 0; *index = 0; @@ -78,16 +82,43 @@ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern); if (!rc) return 0; - - rpat = FcFontMatch(priv->config, pat, &result); - if (!rpat) - return 0; - - result = FcPatternGetBool(rpat, FC_OUTLINE, 0, &val_b); - if (result != FcResultMatch) - return 0; - if (val_b != FcTrue) + + fset = FcFontSort(priv->config, pat, FcTrue, NULL, &result); + + bestf = -1; + if (charset) + bestdiff = FcCharSetCount(charset) + 1; + for (curf = 0; curf < fset->nfont; ++curf) { + rpat = fset->fonts[curf]; + + result = FcPatternGetBool(rpat, FC_OUTLINE, 0, &val_b); + if (result != FcResultMatch) + continue; + if (val_b != FcTrue) + continue; + + if (charset) { + int diff; + result = FcPatternGetCharSet(rpat, FC_CHARSET, 0, &val_cs); + if (result != FcResultMatch) + continue; + diff = FcCharSetSubtractCount(charset, val_cs); + if (diff < bestdiff) { + bestdiff = diff; + bestf = curf; + } + if (diff == 0) + break; + } else { + bestf = curf; + break; + } + } + + if (bestf < 0) return 0; + + rpat = fset->fonts[bestf]; result = FcPatternGetInteger(rpat, FC_INDEX, 0, &val_i); if (result != FcResultMatch) @@ -118,13 +149,14 @@ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold * \param index out: font index inside a file * \return font file path */ -char* fontconfig_select(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index) +char* fontconfig_select_with_charset(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index, + FcCharSet* charset) { char* res = 0; if (family && *family) - res = _select_font(priv, family, bold, italic, index); + res = _select_font(priv, family, bold, italic, index, charset); if (!res && priv->family_default) { - res = _select_font(priv, priv->family_default, bold, italic, index); + res = _select_font(priv, priv->family_default, bold, italic, index, charset); if (res) mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_UsingDefaultFontFamily, family, bold, italic, res, *index); @@ -136,7 +168,7 @@ char* fontconfig_select(fc_instance_t* priv, const char* family, unsigned bold, family, bold, italic, res, *index); } if (!res) { - res = _select_font(priv, "Arial", bold, italic, index); + res = _select_font(priv, "Arial", bold, italic, index, charset); if (res) mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_UsingArialFontFamily, family, bold, italic, res, *index); @@ -147,6 +179,11 @@ char* fontconfig_select(fc_instance_t* priv, const char* family, unsigned bold, return res; } +char* fontconfig_select(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index) +{ + return fontconfig_select_with_charset(priv, family, bold, italic, index, 0); +} + /** * \brief Init fontconfig. * \param dir additional directoryu for fonts diff --git a/libass/ass_fontconfig.h b/libass/ass_fontconfig.h index e2e71a9fd9..9aa1746908 100644 --- a/libass/ass_fontconfig.h +++ b/libass/ass_fontconfig.h @@ -21,11 +21,19 @@ #ifndef __ASS_FONTCONFIG_H__ #define __ASS_FONTCONFIG_H__ +#ifdef HAVE_FONTCONFIG +#include +#endif + typedef struct fc_instance_s fc_instance_t; fc_instance_t* fontconfig_init(const char* dir, const char* family, const char* path); char* fontconfig_select(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index); void fontconfig_done(fc_instance_t* priv); +#ifdef HAVE_FONTCONFIG +char* fontconfig_select_with_charset(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index, FcCharSet* charset); +#endif + #endif -- cgit v1.2.3