changeset 21351:c611dfc4cb85

If a glyph is not found in the current font, switch to another one.
author eugeni
date Tue, 28 Nov 2006 22:50:02 +0000
parents 5337cdeec169
children 2d786b7625d7
files help/help_mp-en.h libass/ass_font.c libass/ass_font.h libass/ass_fontconfig.c libass/ass_fontconfig.h
diffstat 5 files changed, 124 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/help/help_mp-en.h	Tue Nov 28 22:44:40 2006 +0000
+++ b/help/help_mp-en.h	Tue Nov 28 22:50:02 2006 +0000
@@ -2041,3 +2041,6 @@
 #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"
--- a/libass/ass_font.c	Tue Nov 28 22:44:40 2006 +0000
+++ b/libass/ass_font.c	Tue Nov 28 22:50:02 2006 +0000
@@ -86,6 +86,10 @@
 	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 @@
 	}
 }
 
+#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 @@
 		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 @@
 	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);
 }
--- a/libass/ass_font.h	Tue Nov 28 22:44:40 2006 +0000
+++ b/libass/ass_font.h	Tue Nov 28 22:50:02 2006 +0000
@@ -21,6 +21,10 @@
 #ifndef __ASS_FONT_H__
 #define __ASS_FONT_H__
 
+#ifdef HAVE_FONTCONFIG
+#include <fontconfig/fontconfig.h>
+#endif
+
 typedef struct ass_font_desc_s {
 	char* family;
 	unsigned bold;
@@ -36,6 +40,9 @@
 	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);
--- a/libass/ass_fontconfig.c	Tue Nov 28 22:44:40 2006 +0000
+++ b/libass/ass_fontconfig.c	Tue Nov 28 22:50:02 2006 +0000
@@ -53,7 +53,8 @@
  * \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 @@
 	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 @@
 	rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern);
 	if (!rc)
 		return 0;
-	
-	rpat = FcFontMatch(priv->config, pat, &result);
-	if (!rpat)
+
+	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;
-	
-	result = FcPatternGetBool(rpat, FC_OUTLINE, 0, &val_b);
-	if (result != FcResultMatch)
-		return 0;
-	if (val_b != FcTrue)
-		return 0;
+
+	rpat = fset->fonts[bestf];
 	
 	result = FcPatternGetInteger(rpat, FC_INDEX, 0, &val_i);
 	if (result != FcResultMatch)
@@ -118,13 +149,14 @@
  * \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 @@
 		       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 @@
 	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
--- a/libass/ass_fontconfig.h	Tue Nov 28 22:44:40 2006 +0000
+++ b/libass/ass_fontconfig.h	Tue Nov 28 22:50:02 2006 +0000
@@ -21,11 +21,19 @@
 #ifndef __ASS_FONTCONFIG_H__
 #define __ASS_FONTCONFIG_H__
 
+#ifdef HAVE_FONTCONFIG
+#include <fontconfig/fontconfig.h>
+#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
+