summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGrigori Goronzy <greg@kinoho.net>2015-09-07 11:32:49 +0200
committerGrigori Goronzy <greg@kinoho.net>2015-09-07 11:32:49 +0200
commit0268c64b8ec7bef9287a212759152bf7d15e64d8 (patch)
treef421fa82ffeec2c8a4fd10a3a17f6d87fd6977a6
parentfda28f6106caf7d450847444a363adc042b325b9 (diff)
parentd6bb9af645526a810512eaf2c65252ac0e0e6b36 (diff)
downloadlibass-0268c64b8ec7bef9287a212759152bf7d15e64d8.tar.bz2
libass-0268c64b8ec7bef9287a212759152bf7d15e64d8.tar.xz
Merge pull request #190 from grigorig/fonts
Substitutions and some fixes
-rw-r--r--libass/ass_coretext.c14
-rw-r--r--libass/ass_directwrite.c14
-rw-r--r--libass/ass_font.c5
-rw-r--r--libass/ass_fontconfig.c19
-rw-r--r--libass/ass_fontselect.c103
-rw-r--r--libass/ass_fontselect.h31
-rw-r--r--test/test.c2
7 files changed, 144 insertions, 44 deletions
diff --git a/libass/ass_coretext.c b/libass/ass_coretext.c
index 3553324..877018d 100644
--- a/libass/ass_coretext.c
+++ b/libass/ass_coretext.c
@@ -25,6 +25,12 @@
#define SAFE_CFRelease(x) do { if (x) CFRelease(x); } while(0)
+static const ASS_FontMapping font_substitutions[] = {
+ {"sans-serif", "Helvetica"},
+ {"serif", "Times"},
+ {"monospace", "Courier"}
+};
+
static char *cfstr2buf(CFStringRef string)
{
const int encoding = kCFStringEncodingUTF8;
@@ -266,10 +272,18 @@ static char *get_fallback(void *priv, const char *family, uint32_t codepoint)
return res_family;
}
+static void get_substitutions(void *priv, const char *name,
+ ASS_FontProviderMetaData *meta)
+{
+ const int n = sizeof(font_substitutions) / sizeof(font_substitutions[0]);
+ ass_map_font(font_substitutions, n, name, meta);
+}
+
static ASS_FontProviderFuncs coretext_callbacks = {
.check_glyph = check_glyph,
.destroy_font = destroy_font,
.match_fonts = match_fonts,
+ .get_substitutions = get_substitutions,
.get_fallback = get_fallback,
};
diff --git a/libass/ass_directwrite.c b/libass/ass_directwrite.c
index 86b0b4b..f11deb6 100644
--- a/libass/ass_directwrite.c
+++ b/libass/ass_directwrite.c
@@ -31,6 +31,12 @@
#define NAME_MAX_LENGTH 256
#define FALLBACK_DEFAULT_FONT L"Arial"
+static const ASS_FontMapping font_substitutions[] = {
+ {"sans-serif", "Arial"},
+ {"serif", "Times New Roman"},
+ {"monospace", "Courier New"}
+};
+
/*
* The private data stored for every font, detected by this backend.
*/
@@ -624,6 +630,13 @@ static void scan_fonts(IDWriteFactory *factory,
}
}
+static void get_substitutions(void *priv, const char *name,
+ ASS_FontProviderMetaData *meta)
+{
+ const int n = sizeof(font_substitutions) / sizeof(font_substitutions[0]);
+ ass_map_font(font_substitutions, n, name, meta);
+}
+
/*
* Called by libass when the provider should perform the
* specified task
@@ -633,6 +646,7 @@ static ASS_FontProviderFuncs directwrite_callbacks = {
.check_glyph = check_glyph,
.destroy_font = destroy_font,
.destroy_provider = destroy_provider,
+ .get_substitutions = get_substitutions,
.get_fallback = get_fallback,
};
diff --git a/libass/ass_font.c b/libass/ass_font.c
index 0164b67..b3c639d 100644
--- a/libass/ass_font.c
+++ b/libass/ass_font.c
@@ -153,7 +153,6 @@ static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch)
if (font->faces_uid[i] == uid) {
ass_msg(font->library, MSGL_INFO,
"Got a font face that already is available! Skipping.");
- free(path);
return i;
}
}
@@ -178,7 +177,6 @@ static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch)
if (error) {
ass_msg(font->library, MSGL_WARN,
"Error opening memory font: '%s'", path);
- free(path);
return -1;
}
@@ -187,7 +185,6 @@ static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch)
if (error) {
ass_msg(font->library, MSGL_WARN,
"Error opening font: '%s', %d", path, index);
- free(path);
return -1;
}
@@ -201,7 +198,6 @@ static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch)
if (error) {
ass_msg(font->library, MSGL_WARN,
"Error opening font: '%s', %d", path, i);
- free(path);
return -1;
}
@@ -217,7 +213,6 @@ static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch)
font->faces[font->n_faces] = face;
font->faces_uid[font->n_faces++] = uid;
ass_face_set_size(face, font->size);
- free(path);
return font->n_faces - 1;
}
diff --git a/libass/ass_fontconfig.c b/libass/ass_fontconfig.c
index e97102b..184f090 100644
--- a/libass/ass_fontconfig.c
+++ b/libass/ass_fontconfig.c
@@ -177,6 +177,17 @@ static char *get_fallback(void *priv, const char *family, uint32_t codepoint)
if (!fc->fallbacks || fc->fallbacks->nfont == 0)
return NULL;
+ if (codepoint == 0) {
+ char *family = NULL;
+ result = FcPatternGetString(fc->fallbacks->fonts[0], FC_FAMILY, 0,
+ (FcChar8 **)&family);
+ if (result == FcResultMatch) {
+ return strdup(family);
+ } else {
+ return NULL;
+ }
+ }
+
// fallback_chars is the union of all available charsets, so
// if we can't find the glyph in there, the system does not
// have any font to render this glyph.
@@ -194,8 +205,11 @@ static char *get_fallback(void *priv, const char *family, uint32_t codepoint)
char *family = NULL;
result = FcPatternGetString(pattern, FC_FAMILY, 0,
(FcChar8 **)&family);
- family = strdup(family);
- return family;
+ if (result == FcResultMatch) {
+ return strdup(family);
+ } else {
+ return NULL;
+ }
}
}
@@ -275,6 +289,7 @@ ass_fontconfig_add_provider(ASS_Library *lib, ASS_FontSelector *selector,
ass_msg(lib, MSGL_FATAL,
"No valid fontconfig configuration found!");
FcConfigDestroy(fc->config);
+ free(fc);
return NULL;
}
diff --git a/libass/ass_fontselect.c b/libass/ass_fontselect.c
index 95d8c95..d48b170 100644
--- a/libass/ass_fontselect.c
+++ b/libass/ass_fontselect.c
@@ -477,41 +477,19 @@ static int check_glyph(ASS_FontInfo *fi, uint32_t code)
return provider->funcs.check_glyph(fi->priv, code);
}
-static char *select_font(ASS_FontSelector *priv, ASS_Library *library,
- const char *family, unsigned bold, unsigned italic,
- int *index, char **postscript_name, int *uid,
- ASS_FontStream *stream, uint32_t code)
+static char *
+find_font(ASS_FontSelector *priv, ASS_Library *library,
+ ASS_FontProviderMetaData meta, unsigned bold, unsigned italic,
+ int *index, char **postscript_name, int *uid, ASS_FontStream *stream,
+ uint32_t code, bool *name_match)
{
ASS_FontInfo req = {0};
- char *family_trim = strdup_trimmed(family);
- ASS_FontProvider *default_provider = priv->default_provider;
- ASS_FontProviderMetaData meta = {0};
ASS_FontInfo *selected = NULL;
- if (family_trim == NULL)
- return NULL;
-
- if (default_provider && default_provider->funcs.match_fonts)
- default_provider->funcs.match_fonts(library, default_provider, family_trim);
-
// do we actually have any fonts?
if (!priv->n_font)
return NULL;
- ASS_FontProviderMetaData default_meta = {
- .n_fullname = 1,
- .fullnames = &family_trim,
- };
-
- // get a list of substitutes if applicable, and use it for matching
- if (default_provider && default_provider->funcs.get_substitutions) {
- default_provider->funcs.get_substitutions(default_provider->priv,
- family_trim, &meta);
- }
- if (!meta.n_fullname) {
- meta = default_meta;
- }
-
// fill font request
req.slant = italic;
req.weight = bold;
@@ -530,11 +508,13 @@ static char *select_font(ASS_FontSelector *priv, ASS_Library *library,
// If there's a family match, compare font attributes
// to determine best match in that particular family
score = font_attributes_similarity(font, &req);
+ *name_match = true;
} else if (matches_fullname(font, fullname)) {
// If we don't have any match, compare fullnames against request
// if there is a match now, assign lowest score possible. This means
// the font should be chosen instantly, without further search.
score = 0;
+ *name_match = true;
}
// Consider updating idx if score is better than current minimum
@@ -580,13 +560,68 @@ static char *select_font(ASS_FontSelector *priv, ASS_Library *library,
ASS_FontProvider *provider = selected->provider;
stream->func = provider->funcs.get_data;
stream->priv = selected->priv;
- // FIXME: we should define a default family name in some way,
- // possibly the first (or last) English name
- result = strdup(selected->families[0]);
+ // Prefer PostScript name because it is unique. This is only
+ // used for display purposes so it doesn't matter that much,
+ // though.
+ if (selected->postscript_name)
+ result = selected->postscript_name;
+ else
+ result = selected->families[0];
} else
- result = strdup(selected->path);
+ result = selected->path;
+ }
+
+ return result;
+}
+
+static char *select_font(ASS_FontSelector *priv, ASS_Library *library,
+ const char *family, unsigned bold, unsigned italic,
+ int *index, char **postscript_name, int *uid,
+ ASS_FontStream *stream, uint32_t code)
+{
+ ASS_FontProvider *default_provider = priv->default_provider;
+ ASS_FontProviderMetaData meta = {0};
+ char *family_trim = strdup_trimmed(family);
+ char *result = NULL;
+ bool name_match = false;
+
+ if (family_trim == NULL)
+ return NULL;
+
+ ASS_FontProviderMetaData default_meta = {
+ .n_fullname = 1,
+ .fullnames = &family_trim,
+ };
+
+ // Get a list of substitutes if applicable, and use it for matching.
+ if (default_provider && default_provider->funcs.get_substitutions) {
+ default_provider->funcs.get_substitutions(default_provider->priv,
+ family_trim, &meta);
+ }
+
+ if (!meta.n_fullname) {
+ meta = default_meta;
}
+ result = find_font(priv, library, meta, bold, italic, index,
+ postscript_name, uid, stream, code, &name_match);
+
+ // If no matching font was found, it might not exist in the font list
+ // yet. Call the match_fonts callback to fill in the missing fonts
+ // on demand, and retry the search for a match.
+ if (result == NULL && name_match == false && default_provider &&
+ default_provider->funcs.match_fonts) {
+ // TODO: consider changing the API to make more efficient
+ // implementations possible.
+ for (int i = 0; i < meta.n_fullname; i++) {
+ default_provider->funcs.match_fonts(library, default_provider,
+ meta.fullnames[i]);
+ }
+ result = find_font(priv, library, meta, bold, italic, index,
+ postscript_name, uid, stream, code, &name_match);
+ }
+
+ // cleanup
free(family_trim);
if (meta.fullnames != default_meta.fullnames) {
for (int i = 0; i < meta.n_fullname; i++)
@@ -637,7 +672,7 @@ char *ass_font_select(ASS_FontSelector *priv, ASS_Library *library,
if (!search_family || !*search_family)
search_family = "Arial";
char *fallback_family = default_provider->funcs.get_fallback(
- default_provider->priv, family, code);
+ default_provider->priv, search_family, code);
if (fallback_family) {
res = select_font(priv, library, fallback_family, bold, italic,
@@ -1000,10 +1035,6 @@ void ass_fontselect_free(ASS_FontSelector *priv)
if (priv->embedded_provider)
ass_font_provider_free(priv->embedded_provider);
- // XXX: not quite sure, maybe we should track all registered
- // providers and free them right here. or should that be the
- // responsibility of the library user?
-
free(priv->font_infos);
free(priv->path_default);
free(priv->family_default);
diff --git a/libass/ass_fontselect.h b/libass/ass_fontselect.h
index c989e1a..1e0959e 100644
--- a/libass/ass_fontselect.h
+++ b/libass/ass_fontselect.h
@@ -177,6 +177,37 @@ struct ass_font_stream {
void *priv;
};
+
+typedef struct ass_font_mapping ASS_FontMapping;
+
+struct ass_font_mapping {
+ const char *from;
+ const char *to;
+};
+
+/**
+ * Simple font substitution helper. This can be used to implement basic
+ * mappings from one name to another. This is useful for supporting
+ * generic font families in font providers.
+ *
+ * \param map list of mappings
+ * \param len length of list of mappings
+ * \param name font name to map from
+ * \param meta metadata struct, mapped fonts will be stored into this
+ */
+inline void ass_map_font(const ASS_FontMapping *map, int len, const char *name,
+ ASS_FontProviderMetaData *meta)
+{
+ for (int i = 0; i < len; i++) {
+ if (strcasecmp(map[i].from, name) == 0) {
+ meta->n_fullname = 1;
+ meta->fullnames = calloc(1, sizeof(char *));
+ meta->fullnames[0] = strdup(map[i].to);
+ return;
+ }
+ }
+}
+
ASS_FontSelector *
ass_fontselect_init(ASS_Library *library,
FT_Library ftlibrary, const char *family,
diff --git a/test/test.c b/test/test.c
index 175e8be..4884b28 100644
--- a/test/test.c
+++ b/test/test.c
@@ -107,7 +107,7 @@ static void init(int frame_w, int frame_h)
}
ass_set_frame_size(ass_renderer, frame_w, frame_h);
- ass_set_fonts(ass_renderer, NULL, "Sans",
+ ass_set_fonts(ass_renderer, NULL, "sans-serif",
ASS_FONTPROVIDER_AUTODETECT, NULL, 1);
}