summaryrefslogtreecommitdiffstats
path: root/libass
diff options
context:
space:
mode:
authorGrigori Goronzy <greg@chown.ath.cx>2011-08-07 02:21:09 +0200
committerGrigori Goronzy <greg@chown.ath.cx>2015-07-10 10:41:01 +0200
commitc22a4ff9a395546637dbe0f1e9d0ee549dd0069a (patch)
tree40540f98c0faed9e3bac99ecc5caa0ef16b3aa92 /libass
parentd787615845d78d8f8e6d1a4ffc3dc3eecd8a92f6 (diff)
downloadlibass-c22a4ff9a395546637dbe0f1e9d0ee549dd0069a.tar.bz2
libass-c22a4ff9a395546637dbe0f1e9d0ee549dd0069a.tar.xz
Custom font matching and font sources
Implement a simple font sorter (FontSelector) and an interface to deal with multiple font sources (FontProvider). Unfinished business, but works for the most part. Currently the only implemented FontProvider uses fontconfig.
Diffstat (limited to 'libass')
-rw-r--r--libass/Makefile.am7
-rw-r--r--libass/ass_cache.c4
-rw-r--r--libass/ass_font.c30
-rw-r--r--libass/ass_font.h10
-rw-r--r--libass/ass_fontconfig.c593
-rw-r--r--libass/ass_fontconfig.h32
-rw-r--r--libass/ass_fontselect.c514
-rw-r--r--libass/ass_fontselect.h74
-rw-r--r--libass/ass_parse.c3
-rw-r--r--libass/ass_render.c11
-rw-r--r--libass/ass_render.h4
-rw-r--r--libass/ass_render_api.c12
-rw-r--r--libass/ass_shaper.c2
13 files changed, 733 insertions, 563 deletions
diff --git a/libass/Makefile.am b/libass/Makefile.am
index 4bf9584..b8659e6 100644
--- a/libass/Makefile.am
+++ b/libass/Makefile.am
@@ -20,14 +20,13 @@ SRC_INTEL_RASTERIZER = x86/rasterizer.asm
SRC_RASTERIZER = ass_rasterizer.h ass_rasterizer.c ass_rasterizer_c.c
lib_LTLIBRARIES = libass.la
-libass_la_SOURCES = ass.c ass_cache.c ass_font.c ass_fontconfig.c ass_render.c \
+libass_la_SOURCES = ass.c ass_cache.c ass_font.c ass_fontselect.c ass_render.c \
ass_utils.c ass_bitmap.c ass_blur.c ass_library.c ass_bitmap.h \
- ass_cache.h ass_fontconfig.h ass_font.h ass.h \
+ ass_cache.h ass_fontselect.h ass_font.h ass.h \
ass_library.h ass_types.h ass_utils.h ass_drawing.c \
ass_drawing.h ass_cache_template.h ass_render.h \
ass_parse.c ass_parse.h ass_render_api.c ass_shaper.c \
- ass_shaper.h ass_strtod.c ass_func_template.h
-
+ ass_shaper.h ass_strtod.c ass_fontconfig.c ass_fontconfig.h
libass_la_LDFLAGS = -no-undefined -version-info $(LIBASS_LT_CURRENT):$(LIBASS_LT_REVISION):$(LIBASS_LT_AGE)
libass_la_LDFLAGS += -export-symbols $(srcdir)/libass.sym
diff --git a/libass/ass_cache.c b/libass/ass_cache.c
index 2381e88..d1aaec0 100644
--- a/libass/ass_cache.c
+++ b/libass/ass_cache.c
@@ -43,8 +43,6 @@ static unsigned font_hash(void *buf, size_t len)
hval = fnv_32a_str(desc->family, FNV1_32A_INIT);
hval = fnv_32a_buf(&desc->bold, sizeof(desc->bold), hval);
hval = fnv_32a_buf(&desc->italic, sizeof(desc->italic), hval);
- hval = fnv_32a_buf(&desc->treat_family_as_pattern,
- sizeof(desc->treat_family_as_pattern), hval);
hval = fnv_32a_buf(&desc->vertical, sizeof(desc->vertical), hval);
return hval;
}
@@ -59,8 +57,6 @@ static unsigned font_compare(void *key1, void *key2, size_t key_size)
return 0;
if (a->italic != b->italic)
return 0;
- if (a->treat_family_as_pattern != b->treat_family_as_pattern)
- return 0;
if (a->vertical != b->vertical)
return 0;
return 1;
diff --git a/libass/ass_font.c b/libass/ass_font.c
index 5a2645e..13ec654 100644
--- a/libass/ass_font.c
+++ b/libass/ass_font.c
@@ -31,7 +31,7 @@
#include "ass.h"
#include "ass_library.h"
#include "ass_font.h"
-#include "ass_fontconfig.h"
+#include "ass_fontselect.h"
#include "ass_utils.h"
#include "ass_shaper.h"
@@ -127,7 +127,7 @@ static void buggy_font_workaround(FT_Face face)
* \brief Select a face with the given charcode and add it to ASS_Font
* \return index of the new face in font->faces, -1 if failed
*/
-static int add_face(void *fc_priv, ASS_Font *font, uint32_t ch)
+static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch)
{
char *path;
int index;
@@ -138,10 +138,9 @@ static int add_face(void *fc_priv, ASS_Font *font, uint32_t ch)
if (font->n_faces == ASS_FONT_MAX_FACES)
return -1;
- path =
- fontconfig_select(font->library, fc_priv, font->desc.family,
- font->desc.treat_family_as_pattern,
- font->desc.bold, font->desc.italic, &index, ch);
+ path = ass_font_select(fontsel, font->library, font->desc.family,
+ font->desc.bold, font->desc.italic, &index, ch);
+
if (!path)
return -1;
@@ -181,7 +180,7 @@ static int add_face(void *fc_priv, ASS_Font *font, uint32_t ch)
* \brief Create a new ASS_Font according to "desc" argument
*/
ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library,
- FT_Library ftlibrary, void *fc_priv,
+ FT_Library ftlibrary, ASS_FontSelector *fontsel,
ASS_FontDesc *desc)
{
int error;
@@ -197,7 +196,6 @@ ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library,
font.shaper_priv = NULL;
font.n_faces = 0;
font.desc.family = strdup(desc->family);
- font.desc.treat_family_as_pattern = desc->treat_family_as_pattern;
font.desc.bold = desc->bold;
font.desc.italic = desc->italic;
font.desc.vertical = desc->vertical;
@@ -206,7 +204,7 @@ ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library,
font.v.x = font.v.y = 0;
font.size = 0.;
- error = add_face(fc_priv, &font, 0);
+ error = add_face(fontsel, &font, 0);
if (error == -1) {
free(font.desc.family);
return 0;
@@ -484,8 +482,8 @@ static void ass_glyph_embolden(FT_GlyphSlot slot)
* Finds a face that has the requested codepoint and returns both face
* and glyph index.
*/
-int ass_font_get_index(void *fcpriv, ASS_Font *font, uint32_t symbol,
- int *face_index, int *glyph_index)
+int ass_font_get_index(ASS_FontSelector *fontsel, ASS_Font *font,
+ uint32_t symbol, int *face_index, int *glyph_index)
{
int index = 0;
int i;
@@ -519,14 +517,13 @@ int ass_font_get_index(void *fcpriv, ASS_Font *font, uint32_t symbol,
*face_index = i;
}
-#ifdef CONFIG_FONTCONFIG
if (index == 0) {
int face_idx;
ass_msg(font->library, MSGL_INFO,
"Glyph 0x%X not found, selecting one more "
"font for (%s, %d, %d)", symbol, font->desc.family,
font->desc.bold, font->desc.italic);
- face_idx = *face_index = add_face(fcpriv, font, symbol);
+ face_idx = *face_index = add_face(fontsel, font, symbol);
if (face_idx >= 0) {
face = font->faces[face_idx];
index = FT_Get_Char_Index(face, ass_font_index_magic(face, symbol));
@@ -547,7 +544,7 @@ int ass_font_get_index(void *fcpriv, ASS_Font *font, uint32_t symbol,
}
}
}
-#endif
+
// FIXME: make sure we have a valid face_index. this is a HACK.
*face_index = FFMAX(*face_index, 0);
*glyph_index = index;
@@ -559,9 +556,8 @@ int ass_font_get_index(void *fcpriv, ASS_Font *font, uint32_t symbol,
* \brief Get a glyph
* \param ch character code
**/
-FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font,
- uint32_t ch, int face_index, int index,
- ASS_Hinting hinting, int deco)
+FT_Glyph ass_font_get_glyph(ASS_Font *font, uint32_t ch, int face_index,
+ int index, ASS_Hinting hinting, int deco)
{
int error;
FT_Glyph glyph;
diff --git a/libass/ass_font.h b/libass/ass_font.h
index f3c3f8e..9ccc83a 100644
--- a/libass/ass_font.h
+++ b/libass/ass_font.h
@@ -26,6 +26,7 @@
#include "ass.h"
#include "ass_types.h"
+#include "ass_fontselect.h"
#define VERTICAL_LOWER_BOUND 0x02f1
@@ -39,7 +40,6 @@ typedef struct {
char *family;
unsigned bold;
unsigned italic;
- int treat_family_as_pattern;
int vertical; // @font vertical layout
} ASS_FontDesc;
@@ -58,7 +58,7 @@ typedef struct {
#include "ass_cache.h"
ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library,
- FT_Library ftlibrary, void *fc_priv,
+ FT_Library ftlibrary, ASS_FontSelector *fontsel,
ASS_FontDesc *desc);
void ass_font_set_transform(ASS_Font *font, double scale_x,
double scale_y, FT_Vector *v);
@@ -66,10 +66,10 @@ void ass_face_set_size(FT_Face face, double size);
void ass_font_set_size(ASS_Font *font, double size);
void ass_font_get_asc_desc(ASS_Font *font, uint32_t ch, int *asc,
int *desc);
-int ass_font_get_index(void *fcpriv, ASS_Font *font, uint32_t symbol,
- int *face_index, int *glyph_index);
+int ass_font_get_index(ASS_FontSelector *fontsel, ASS_Font *font,
+ uint32_t symbol, int *face_index, int *glyph_index);
uint32_t ass_font_index_magic(FT_Face face, uint32_t symbol);
-FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font,
+FT_Glyph ass_font_get_glyph(ASS_Font *font,
uint32_t ch, int face_index, int index,
ASS_Hinting hinting, int deco);
FT_Vector ass_font_get_kerning(ASS_Font *font, uint32_t c1, uint32_t c2);
diff --git a/libass/ass_fontconfig.c b/libass/ass_fontconfig.c
index f0e9000..c65cd20 100644
--- a/libass/ass_fontconfig.c
+++ b/libass/ass_fontconfig.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
+ * Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
*
* This file is part of libass.
*
@@ -18,545 +18,144 @@
#include "config.h"
-#include <stdlib.h>
+#ifdef CONFIG_FONTCONFIG
+
#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-#include <strings.h>
+#include <stdlib.h>
#include <sys/types.h>
-#include <sys/stat.h>
-#include <inttypes.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include "ass_utils.h"
-#include "ass.h"
-#include "ass_library.h"
-#include "ass_fontconfig.h"
-
-#ifdef CONFIG_FONTCONFIG
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
-#endif
-
-struct fc_instance {
-#ifdef CONFIG_FONTCONFIG
- FcConfig *config;
-#endif
- char *family_default;
- char *path_default;
- int index_default;
-};
-
-#ifdef CONFIG_FONTCONFIG
-/**
- * \brief Case-insensitive match ASS/SSA font family against full name. (also
- * known as "name for humans")
- *
- * \param lib library instance
- * \param priv fontconfig instance
- * \param family font fullname
- * \param bold weight attribute
- * \param italic italic attribute
- * \return font set
- */
-static FcFontSet *
-match_fullname(ASS_Library *lib, FCInstance *priv, const char *family,
- unsigned bold, unsigned italic)
-{
- FcFontSet *sets[2];
- FcFontSet *result = FcFontSetCreate();
- int nsets = 0;
- int i, fi;
-
- if (!result)
- return NULL;
-
- if ((sets[nsets] = FcConfigGetFonts(priv->config, FcSetSystem)))
- nsets++;
- if ((sets[nsets] = FcConfigGetFonts(priv->config, FcSetApplication)))
- nsets++;
-
- // Run over font sets and patterns and try to match against full name
- for (i = 0; i < nsets; i++) {
- FcFontSet *set = sets[i];
- for (fi = 0; fi < set->nfont; fi++) {
- FcPattern *pat = set->fonts[fi];
- char *fullname;
- int pi = 0, at;
- FcBool ol;
- while (FcPatternGetString(pat, FC_FULLNAME, pi++,
- (FcChar8 **) &fullname) == FcResultMatch) {
- if (FcPatternGetBool(pat, FC_OUTLINE, 0, &ol) != FcResultMatch
- || ol != FcTrue)
- continue;
- if (FcPatternGetInteger(pat, FC_SLANT, 0, &at) != FcResultMatch
- || at < italic)
- continue;
- if (FcPatternGetInteger(pat, FC_WEIGHT, 0, &at) != FcResultMatch
- || at < bold)
- continue;
- if (strcasecmp(fullname, family) == 0) {
- FcFontSetAdd(result, FcPatternDuplicate(pat));
- break;
- }
- }
- }
- }
+#include "ass_fontconfig.h"
+#include "ass_fontselect.h"
+#include "ass_utils.h"
- return result;
-}
+#define MAX_FULLNAME 100
-/**
- * \brief Low-level font selection.
- * \param priv private data
- * \param family font family
- * \param treat_family_as_pattern treat family as fontconfig pattern
- * \param bold font weight value
- * \param italic font slant value
- * \param index out: font index inside a file
- * \param code: the character that should be present in the font, can be 0
- * \return font file path
-*/
-static char *select_font(ASS_Library *library, FCInstance *priv,
- const char *family, int treat_family_as_pattern,
- unsigned bold, unsigned italic, int *index,
- uint32_t code)
+static int check_glyph(void *priv, uint32_t code)
{
- FcBool rc;
- FcResult result;
- FcPattern *pat = NULL, *rpat = NULL;
- int r_index, r_slant, r_weight;
- FcChar8 *r_family, *r_style, *r_file, *r_fullname;
- FcBool r_outline, r_embolden;
- FcCharSet *r_charset;
- FcFontSet *ffullname = NULL, *fsorted = NULL, *fset = NULL;
- int curf;
- char *retval = NULL;
- int family_cnt = 0;
-
- *index = 0;
-
- if (treat_family_as_pattern)
- pat = FcNameParse((const FcChar8 *) family);
- else
- pat = FcPatternCreate();
+ FcPattern *pat = (FcPattern *)priv;
+ FcCharSet *charset;
if (!pat)
- goto error;
-
- if (!treat_family_as_pattern) {
- FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *) family);
+ return 1;
- // In SSA/ASS fonts are sometimes referenced by their "full name",
- // which is usually a concatenation of family name and font
- // style (ex. Ottawa Bold). Full name is available from
- // FontConfig pattern element FC_FULLNAME, but it is never
- // used for font matching.
- // Therefore, I'm removing words from the end of the name one
- // by one, and adding shortened names to the pattern. It seems
- // that the first value (full name in this case) has
- // precedence in matching.
- // An alternative approach could be to reimplement FcFontSort
- // using FC_FULLNAME instead of FC_FAMILY.
- family_cnt = 1;
- {
- char *s = strdup(family);
- if (!s)
- goto error;
- char *p = s + strlen(s);
- while (--p > s)
- if (*p == ' ' || *p == '-') {
- *p = '\0';
- FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *) s);
- ++family_cnt;
- }
- free(s);
- }
- }
- FcPatternAddBool(pat, FC_OUTLINE, FcTrue);
- FcPatternAddInteger(pat, FC_SLANT, italic);
- FcPatternAddInteger(pat, FC_WEIGHT, bold);
-
- FcDefaultSubstitute(pat);
-
- rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern);
- if (!rc)
- goto error;
- /* Fontconfig defaults include a language setting, which it sets based on
- * some environment variables or defaults to "en". Unset this as we don't
- * know the real language, and because some some attached fonts lack
- * non-ascii characters included in fontconfig's list of characters
- * required for English support and therefore don't match the lang=en
- * criterion.
- */
- FcPatternDel(pat, "lang");
-
- fsorted = FcFontSort(priv->config, pat, FcFalse, NULL, &result);
- ffullname = match_fullname(library, priv, family, bold, italic);
- if (!fsorted || !ffullname)
- goto error;
-
- fset = FcFontSetCreate();
- for (curf = 0; curf < ffullname->nfont; ++curf) {
- FcPattern *curp = ffullname->fonts[curf];
- FcPatternReference(curp);
- FcFontSetAdd(fset, curp);
- }
- for (curf = 0; curf < fsorted->nfont; ++curf) {
- FcPattern *curp = fsorted->fonts[curf];
- FcPatternReference(curp);
- FcFontSetAdd(fset, curp);
- }
-
- for (curf = 0; curf < fset->nfont; ++curf) {
- FcPattern *curp = fset->fonts[curf];
-
- result = FcPatternGetBool(curp, FC_OUTLINE, 0, &r_outline);
- if (result != FcResultMatch)
- continue;
- if (r_outline != FcTrue)
- continue;
- if (!code)
- break;
- result = FcPatternGetCharSet(curp, FC_CHARSET, 0, &r_charset);
- if (result != FcResultMatch)
- continue;
- if (FcCharSetHasChar(r_charset, code))
- break;
- }
-
- if (curf >= fset->nfont)
- goto error;
-
- if (!treat_family_as_pattern) {
- // Remove all extra family names from original pattern.
- // After this, FcFontRenderPrepare will select the most relevant family
- // name in case there are more than one of them.
- for (; family_cnt > 1; --family_cnt)
- FcPatternRemove(pat, FC_FAMILY, family_cnt - 1);
- }
-
- rpat = FcFontRenderPrepare(priv->config, pat, fset->fonts[curf]);
- if (!rpat)
- goto error;
-
- result = FcPatternGetInteger(rpat, FC_INDEX, 0, &r_index);
- if (result != FcResultMatch)
- goto error;
- *index = r_index;
-
- result = FcPatternGetString(rpat, FC_FILE, 0, &r_file);
- if (result != FcResultMatch)
- goto error;
- retval = strdup((const char *) r_file);
- if (!retval)
- goto error;
-
- result = FcPatternGetString(rpat, FC_FAMILY, 0, &r_family);
- if (result != FcResultMatch)
- r_family = NULL;
-
- result = FcPatternGetString(rpat, FC_FULLNAME, 0, &r_fullname);
- if (result != FcResultMatch)
- r_fullname = NULL;
-
- if (!treat_family_as_pattern &&
- !(r_family && strcasecmp((const char *) r_family, family) == 0) &&
- !(r_fullname && strcasecmp((const char *) r_fullname, family) == 0)) {
- char *fallback = (char *) (r_fullname ? r_fullname : r_family);
- if (code) {
- ass_msg(library, MSGL_WARN,
- "fontconfig: cannot find glyph U+%04X in font '%s', falling back to '%s'",
- (unsigned int)code, family, fallback);
- } else {
- ass_msg(library, MSGL_WARN,
- "fontconfig: cannot find font '%s', falling back to '%s'",
- family, fallback);
- }
- }
+ if (code == 0)
+ return 1;
- result = FcPatternGetString(rpat, FC_STYLE, 0, &r_style);
+ FcResult result = FcPatternGetCharSet(pat, FC_CHARSET, 0, &charset);
if (result != FcResultMatch)
- r_style = NULL;
-
- result = FcPatternGetInteger(rpat, FC_SLANT, 0, &r_slant);
- if (result != FcResultMatch)
- r_slant = 0;
-
- result = FcPatternGetInteger(rpat, FC_WEIGHT, 0, &r_weight);
- if (result != FcResultMatch)
- r_weight = 0;
-
- result = FcPatternGetBool(rpat, FC_EMBOLDEN, 0, &r_embolden);
- if (result != FcResultMatch)
- r_embolden = 0;
-
- ass_msg(library, MSGL_V,
- "Font info: family '%s', style '%s', fullname '%s',"
- " slant %d, weight %d%s", (const char *) r_family,
- (const char *) r_style, (const char *) r_fullname, r_slant,
- r_weight, r_embolden ? ", embolden" : "");
-
- error:
- if (pat)
- FcPatternDestroy(pat);
- if (rpat)
- FcPatternDestroy(rpat);
- if (fsorted)
- FcFontSetDestroy(fsorted);
- if (ffullname)
- FcFontSetDestroy(ffullname);
- if (fset)
- FcFontSetDestroy(fset);
- return retval;
+ return 0;
+ if (FcCharSetHasChar(charset, code) == FcTrue)
+ return 1;
+ return 0;
}
-/**
- * \brief Find a font. Use default family or path if necessary.
- * \param priv_ private data
- * \param family font family
- * \param treat_family_as_pattern treat family as fontconfig pattern
- * \param bold font weight value
- * \param italic font slant value
- * \param index out: font index inside a file
- * \param code: the character that should be present in the font, can be 0
- * \return font file path
-*/
-char *fontconfig_select(ASS_Library *library, FCInstance *priv,
- const char *family, int treat_family_as_pattern,
- unsigned bold, unsigned italic, int *index,
- uint32_t code)
+static void destroy(void *priv)
{
- char *res = 0;
- if (!priv->config) {
- *index = priv->index_default;
- res = priv->path_default ? strdup(priv->path_default) : 0;
- return res;
- }
- if (family && *family)
- res =
- select_font(library, priv, family, treat_family_as_pattern,
- bold, italic, index, code);
- if (!res && priv->family_default) {
- res =
- select_font(library, priv, priv->family_default, 0, bold,
- italic, index, code);
- if (res)
- ass_msg(library, MSGL_WARN, "fontconfig_select: Using default "
- "font family: (%s, %d, %d) -> %s, %d",
- family, bold, italic, res, *index);
- }
- if (!res && priv->path_default) {
- res = strdup(priv->path_default);
- *index = priv->index_default;
- if (res)
- ass_msg(library, MSGL_WARN, "fontconfig_select: Using default font: "
- "(%s, %d, %d) -> %s, %d", family, bold, italic,
- res, *index);
- }
- if (!res) {
- res = select_font(library, priv, "Arial", 0, bold, italic,
- index, code);
- if (res)
- ass_msg(library, MSGL_WARN, "fontconfig_select: Using 'Arial' "
- "font family: (%s, %d, %d) -> %s, %d", family, bold,
- italic, res, *index);
- }
- if (res)
- ass_msg(library, MSGL_V,
- "fontconfig_select: (%s, %d, %d) -> %s, %d", family, bold,
- italic, res, *index);
- return res;
+ FcConfig *config = (FcConfig *)priv;
+ FcConfigDestroy(config);
}
-/**
- * \brief Process memory font.
- * \param priv private data
- * \param library library object
- * \param ftlibrary freetype library object
- * \param idx index of the processed font in library->fontdata
- *
- * Builds a font pattern in memory via FT_New_Memory_Face/FcFreeTypeQueryFace.
-*/
-static void process_fontdata(FCInstance *priv, ASS_Library *library,
- FT_Library ftlibrary, int idx)
+static void scan_fonts(FcConfig *config, ASS_FontProvider *provider)
{
- int rc;
- const char *name = library->fontdata[idx].name;
- const char *data = library->fontdata[idx].data;
- int data_size = library->fontdata[idx].size;
-
- FT_Face face;
- FcPattern *pattern;
- FcFontSet *fset;
- FcBool res;
- int face_index, num_faces = 1;
-
- for (face_index = 0; face_index < num_faces; ++face_index) {
- ass_msg(library, MSGL_V, "Adding memory font '%s'", name);
+ int i;
+ FcFontSet *fonts;
+ ASS_FontProviderMetaData meta;
+
+ // get list of fonts
+ fonts = FcConfigGetFonts(config, FcSetSystem);
+
+ // fill font_info list
+ for (i = 0; i < fonts->nfont; i++) {
+ FcPattern *pat = fonts->fonts[i];
+ FcBool outline;
+ int index;
+ char *path;
+ char *fullnames[MAX_FULLNAME];
+
+ // skip non-outline fonts
+ FcResult result = FcPatternGetBool(pat, FC_OUTLINE, 0, &outline);
+ if (result != FcResultMatch || outline != FcTrue)
+ continue;
- rc = FT_New_Memory_Face(ftlibrary, (unsigned char *) data,
- data_size, face_index, &face);
- if (rc) {
- ass_msg(library, MSGL_WARN, "Error opening memory font: %s",
- name);
- return;
- }
- num_faces = face->num_faces;
+ // simple types
+ result = FcPatternGetInteger(pat, FC_SLANT, 0, &meta.slant);
+ result |= FcPatternGetInteger(pat, FC_WEIGHT, 0, &meta.weight);
+ result |= FcPatternGetInteger(pat, FC_INDEX, 0, &index);
+ if (result != FcResultMatch)
+ continue;
- pattern =
- FcFreeTypeQueryFace(face, (unsigned char *) name, face_index,
- FcConfigGetBlanks(priv->config));
- if (!pattern) {
- ass_msg(library, MSGL_WARN, "%s failed", "FcFreeTypeQueryFace");
- FT_Done_Face(face);
- return;
- }
+ // family name
+ // HACK: get the last family name. that fixes fonts
+ // like Arial Narrow in some versions
+ int n_family = 0;
+ while (FcPatternGetString(pat, FC_FAMILY, n_family,
+ (FcChar8 **)&meta.family) == FcResultMatch)
+ n_family++;
- fset = FcConfigGetFonts(priv->config, FcSetSystem); // somehow it failes when asked for FcSetApplication
- if (!fset) {
- ass_msg(library, MSGL_WARN, "%s failed", "FcConfigGetFonts");
- FT_Done_Face(face);
- return;
- }
+ // path
+ result = FcPatternGetString(pat, FC_FILE, 0, (FcChar8 **)&path);
+ if (result != FcResultMatch)
+ continue;
- res = FcFontSetAdd(fset, pattern);
- if (!res) {
- ass_msg(library, MSGL_WARN, "%s failed", "FcFontSetAdd");
- FT_Done_Face(face);
- return;
- }
+ // read and strdup fullnames
+ meta.n_fullname = 0;
+ while (FcPatternGetString(pat, FC_FULLNAME, meta.n_fullname,
+ (FcChar8 **)&fullnames[meta.n_fullname]) == FcResultMatch
+ && meta.n_fullname < MAX_FULLNAME)
+ meta.n_fullname++;
+ meta.fullnames = fullnames;
- FT_Done_Face(face);
+ ass_font_provider_add_font(provider, &meta, path, index, (void *)pat);
}
}
-/**
- * \brief Init fontconfig.
- * \param library libass library object
- * \param ftlibrary freetype library object
- * \param family default font family
- * \param path default font path
- * \param fc whether fontconfig should be used
- * \param config path to a fontconfig configuration file, or NULL
- * \param update whether the fontconfig cache should be built/updated
- * \return pointer to fontconfig private data
-*/
-FCInstance *fontconfig_init(ASS_Library *library,
- FT_Library ftlibrary, const char *family,
- const char *path, int fc, const char *config,
- int update)
+static ASS_FontProviderFuncs fontconfig_callbacks = {
+ NULL,
+ check_glyph,
+ NULL,
+ destroy
+};
+
+ASS_FontProvider *
+ass_fontconfig_add_provider(ASS_Library *lib, ASS_FontSelector *selector,
+ const char *config)
{
int rc;
- FCInstance *priv = calloc(1, sizeof(FCInstance));
- const char *dir = library->fonts_dir;
- int i;
-
- if (!priv)
- return NULL;
-
- if (!fc) {
- ass_msg(library, MSGL_WARN,
- "Fontconfig disabled, only default font will be used.");
- goto exit;
- }
+ FcConfig *fc_config;
+ ASS_FontProvider *provider = NULL;
- priv->config = FcConfigCreate();
- rc = FcConfigParseAndLoad(priv->config, (unsigned char *) config, FcTrue);
+ // build and load fontconfig configuration
+ fc_config = FcConfigCreate();
+ rc = FcConfigParseAndLoad(fc_config, (unsigned char *) config, FcTrue);
if (!rc) {
- ass_msg(library, MSGL_WARN, "No usable fontconfig configuration "
+ ass_msg(lib, MSGL_WARN, "No usable fontconfig configuration "
"file found, using fallback.");
- FcConfigDestroy(priv->config);
- priv->config = FcInitLoadConfig();
+ FcConfigDestroy(fc_config);
+ fc_config = FcInitLoadConfig();
rc++;
}
- if (rc && update) {
- FcConfigBuildFonts(priv->config);
- }
+ if (rc)
+ FcConfigBuildFonts(fc_config);
- if (!rc || !priv->config) {
- ass_msg(library, MSGL_FATAL,
+ if (!rc || !fc_config) {
+ ass_msg(lib, MSGL_FATAL,
"No valid fontconfig configuration found!");
- FcConfigDestroy(priv->config);
+ FcConfigDestroy(fc_config);
goto exit;
}
- for (i = 0; i < library->num_fontdata; ++i)
- process_fontdata(priv, library, ftlibrary, i);
+ // create font provider
+ provider = ass_font_provider_new(selector, &fontconfig_callbacks,
+ (void *)fc_config);
- if (dir) {
- ass_msg(library, MSGL_V, "Updating font cache");
-
- rc = FcConfigAppFontAddDir(priv->config, (const FcChar8 *) dir);
- if (!rc) {
- ass_msg(library, MSGL_WARN, "%s failed", "FcConfigAppFontAddDir");
- }
- }
+ // scan fonts
+ scan_fonts(fc_config, provider);
- priv->family_default = family ? strdup(family) : NULL;
exit:
- priv->path_default = path ? strdup(path) : NULL;
- priv->index_default = 0;
-
- return priv;
-}
-
-int fontconfig_update(FCInstance *priv)
-{
- return FcConfigBuildFonts(priv->config);
-}
-
-#else /* CONFIG_FONTCONFIG */
-
-char *fontconfig_select(ASS_Library *library, FCInstance *priv,
- const char *family, int treat_family_as_pattern,
- unsigned bold, unsigned italic, int *index,
- uint32_t code)
-{
- *index = priv->index_default;
- char* res = priv->path_default ? strdup(priv->path_default) : 0;
- return res;
-}
-
-FCInstance *fontconfig_init(ASS_Library *library,
- FT_Library ftlibrary, const char *family,
- const char *path, int fc, const char *config,
- int update)
-{
- FCInstance *priv;
-
- ass_msg(library, MSGL_WARN,
- "Fontconfig disabled, only default font will be used.");
-
- priv = calloc(1, sizeof(FCInstance));
- if (!priv)
- return NULL;
-
- priv->path_default = path ? strdup(path) : 0;
- priv->index_default = 0;
- return priv;
-}
-
-int fontconfig_update(FCInstance *priv)
-{
- // Do nothing
- return 1;
+ return provider;
}
#endif
-
-void fontconfig_done(FCInstance *priv)
-{
-
- if (priv) {
-#ifdef CONFIG_FONTCONFIG
- if (priv->config)
- FcConfigDestroy(priv->config);
-#endif
- free(priv->path_default);
- free(priv->family_default);
- }
- free(priv);
-}
diff --git a/libass/ass_fontconfig.h b/libass/ass_fontconfig.h
index 396fb72..6d4f5e9 100644
--- a/libass/ass_fontconfig.h
+++ b/libass/ass_fontconfig.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
+ * Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
*
* This file is part of libass.
*
@@ -16,30 +16,20 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef LIBASS_FONTCONFIG_H
-#define LIBASS_FONTCONFIG_H
+#include "config.h"
-#include <stdint.h>
#include "ass_types.h"
-#include "ass.h"
-#include <ft2build.h>
-#include FT_FREETYPE_H
+#include "ass_fontselect.h"
+
+#ifndef ASS_FONTCONFIG_H
+#define ASS_FONTCONFIG_H
#ifdef CONFIG_FONTCONFIG
-#include <fontconfig/fontconfig.h>
-#endif
-typedef struct fc_instance FCInstance;
+ASS_FontProvider *
+ass_fontconfig_add_provider(ASS_Library *lib, ASS_FontSelector *selector,
+ const char *config);
-FCInstance *fontconfig_init(ASS_Library *library,
- FT_Library ftlibrary, const char *family,
- const char *path, int fc, const char *config,
- int update);
-char *fontconfig_select(ASS_Library *library, FCInstance *priv,
- const char *family, int treat_family_as_pattern,
- unsigned bold, unsigned italic, int *index,
- uint32_t code);
-void fontconfig_done(FCInstance *priv);
-int fontconfig_update(FCInstance *priv);
+#endif
-#endif /* LIBASS_FONTCONFIG_H */
+#endif
diff --git a/libass/ass_fontselect.c b/libass/ass_fontselect.c
new file mode 100644
index 0000000..481d4c9
--- /dev/null
+++ b/libass/ass_fontselect.c
@@ -0,0 +1,514 @@
+/*
+ * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
+ * Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
+ *
+ * This file is part of libass.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permi