/** * \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) { 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); 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; 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; } 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; } res = FcFontSetAdd(fset, pattern); if (!res) { ass_msg(library, MSGL_WARN, "%s failed", "FcFontSetAdd"); FT_Done_Face(face); return; } FT_Done_Face(face); } }
/** * \brief Init fontconfig. * \param library libass library object * \param ftlibrary freetype library object * \param family default font family * \param path default font path * \return pointer to fontconfig private data */ fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, const char* family, const char* path) { int rc; fc_instance_t* priv = calloc(1, sizeof(fc_instance_t)); const char* dir = library->fonts_dir; int i; rc = FcInit(); assert(rc); priv->config = FcConfigGetCurrent(); if (!priv->config) { mp_msg(MSGT_ASS, MSGL_FATAL, MSGTR_LIBASS_FcInitLoadConfigAndFontsFailed); return 0; } for (i = 0; i < library->num_fontdata; ++i) process_fontdata(priv, library, ftlibrary, i); if (FcDirCacheValid((const FcChar8 *)dir) == FcFalse) { mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_UpdatingFontCache); if (FcGetVersion() >= 20390 && FcGetVersion() < 20400) mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_BetaVersionsOfFontconfigAreNotSupported); // FontConfig >= 2.4.0 updates cache automatically in FcConfigAppFontAddDir() if (FcGetVersion() < 20390) { FcFontSet* fcs; FcStrSet* fss; fcs = FcFontSetCreate(); fss = FcStrSetCreate(); rc = FcStrSetAdd(fss, (const FcChar8*)dir); if (!rc) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FcStrSetAddFailed); goto ErrorFontCache; } rc = FcDirScan(fcs, fss, NULL, FcConfigGetBlanks(priv->config), (const FcChar8 *)dir, FcFalse); if (!rc) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FcDirScanFailed); goto ErrorFontCache; } rc = FcDirSave(fcs, fss, (const FcChar8 *)dir); if (!rc) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FcDirSave); goto ErrorFontCache; } ErrorFontCache: ; } } rc = FcConfigAppFontAddDir(priv->config, (const FcChar8*)dir); if (!rc) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FcConfigAppFontAddDirFailed); } priv->family_default = family ? strdup(family) : 0; priv->path_default = path ? strdup(path) : 0; priv->index_default = 0; return priv; }
/** * \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 * With FontConfig >= 2.4.2, builds a font pattern in memory via FT_New_Memory_Face/FcFreeTypeQueryFace. * With older FontConfig versions, save the font to ~/.mplayer/fonts. */ static void process_fontdata(fc_instance_t* priv, ass_library_t* library, FT_Library ftlibrary, int idx) { int rc; const char* name = library->fontdata[idx].name; const char* data = library->fontdata[idx].data; int data_size = library->fontdata[idx].size; #if (FC_VERSION < 20402) struct stat st; char* fname; const char* fonts_dir = library->fonts_dir; char buf[1000]; FILE* fp = 0; if (!fonts_dir) return; rc = stat(fonts_dir, &st); if (rc) { int res; #ifndef __MINGW32__ res = mkdir(fonts_dir, 0700); #else res = mkdir(fonts_dir); #endif if (res) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FailedToCreateDirectory, fonts_dir); } } else if (!S_ISDIR(st.st_mode)) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_NotADirectory, fonts_dir); } fname = validate_fname((char*)name); snprintf(buf, 1000, "%s/%s", fonts_dir, fname); free(fname); fp = fopen(buf, "wb"); if (!fp) return; fwrite(data, data_size, 1, fp); fclose(fp); #else // (FC_VERSION >= 20402) FT_Face face; FcPattern* pattern; FcFontSet* fset; FcBool res; rc = FT_New_Memory_Face(ftlibrary, (unsigned char*)data, data_size, 0, &face); if (rc) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorOpeningMemoryFont, name); return; } pattern = FcFreeTypeQueryFace(face, (unsigned char*)name, 0, FcConfigGetBlanks(priv->config)); if (!pattern) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed, "FcFreeTypeQueryFace"); FT_Done_Face(face); return; } fset = FcConfigGetFonts(priv->config, FcSetSystem); // somehow it failes when asked for FcSetApplication if (!fset) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed, "FcConfigGetFonts"); FT_Done_Face(face); return; } res = FcFontSetAdd(fset, pattern); if (!res) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed, "FcFontSetAdd"); FT_Done_Face(face); return; } FT_Done_Face(face); #endif }
FcBool FcDirScanConfig (FcFontSet *set, FcStrSet *dirs, FcBlanks *blanks, const FcChar8 *dir, FcBool force, /* XXX unused */ FcConfig *config) { DIR *d; struct dirent *e; FcStrSet *files; FcChar8 *file; FcChar8 *base; FcBool ret = FcTrue; int i; if (!force) return FcFalse; if (!set && !dirs) return FcTrue; if (!blanks) blanks = FcConfigGetBlanks (config); /* freed below */ file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); if (!file) { ret = FcFalse; goto bail; } strcpy ((char *) file, (char *) dir); strcat ((char *) file, "/"); base = file + strlen ((char *) file); if (FcDebug () & FC_DBG_SCAN) printf ("\tScanning dir %s\n", dir); d = opendir ((char *) dir); if (!d) { /* Don't complain about missing directories */ if (errno != ENOENT) ret = FcFalse; goto bail; } files = FcStrSetCreate (); if (!files) { ret = FcFalse; goto bail1; } while ((e = readdir (d))) { if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN) { strcpy ((char *) base, (char *) e->d_name); if (!FcStrSetAdd (files, file)) { ret = FcFalse; goto bail2; } } } /* * Sort files to make things prettier */ qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp); /* * Scan file files to build font patterns */ for (i = 0; i < files->num; i++) FcFileScanConfig (set, dirs, blanks, files->strs[i], config); bail2: FcStrSetDestroy (files); bail1: closedir (d); bail: return ret; }
/* no character exists */ FcChar32 fcinfo_chars(FcCharSet *charset, FcChar32 **chars, const char *uinterval, uinterval_type_t uintype, FcBool grid, FcChar32 maxchars) { FcChar32 available, nchars, n; FcBlanks *blanks = FcConfigGetBlanks(NULL); FcChar32 ucs4; FcChar32 map[FC_CHARSET_MAP_SIZE]; FcChar32 next; int i, j, left, right; int nlines; nlines = 0; for (ucs4 = FcCharSetFirstPage (charset, map, &next); ucs4 != FC_CHARSET_DONE; ucs4 = FcCharSetNextPage (charset, map, &next)) { int i; /* for ucs4 == 0, skip i == 0 and i == 4, see below */ for (i = (ucs4 == 0 ? 1 : 0); i < FC_CHARSET_MAP_SIZE; ucs4 == 0 && i == 3 ? i = 5 : i++) if (map[i] && (!uinterval || unicode_interval_contains(uinterval, uintype, ucs4 + 32*i) || unicode_interval_contains(uinterval, uintype, ucs4 + 32*i + 0x10))) nlines++; } if (grid) available = 32*nlines; else available = FcCharSetCount(charset); nchars = available < maxchars ? available : maxchars; *chars = (FcChar32*)malloc(nchars*sizeof(FcChar32)); if (! *chars) { fprintf(stderr, "fcinfo_chars(): can't allocate memory\n"); exit(1); } /* for() code below borrowed from fontconfig-2.10.2/src/fclang.c */ n = 0; for (ucs4 = FcCharSetFirstPage (charset, map, &next); ucs4 != FC_CHARSET_DONE; ucs4 = FcCharSetNextPage (charset, map, &next)) { /* for some fonts (e. g. Dina) fontconfig reports they contain control characters; skip them for sure (we get 'wrong unicode character' while converting svg if not) */ for (i = (ucs4 == 0 ? 1 : 0); i < FC_CHARSET_MAP_SIZE; ucs4 == 0 && i == 3 ? i = 5 : i++) { if (map[i]) { left = 0; right = 32; if (uinterval && !unicode_interval_contains(uinterval, uintype, ucs4 + 32*i)) left = 16; if (uinterval && !unicode_interval_contains(uinterval, uintype, ucs4 + 32*i + 16)) right = 16; for (j = left; j < right; j++) { if (map[i] & (1 << j)) { FcChar32 ch = ucs4 + 32*i + j; if (grid == FcTrue || !FcBlanksIsMember(blanks, ch)) (*chars)[n++] = ch; } else if (grid == FcTrue) (*chars)[n++] = NO_CHAR; if (n == nchars) return n; } } } } return n; }
int main (int argc, char **argv) { int index_set = 0; int set_index = 0; FcChar8 *format = NULL; int err = 0; int i; FcBlanks *blanks; #if HAVE_GETOPT_LONG || HAVE_GETOPT int c; #if HAVE_GETOPT_LONG while ((c = getopt_long (argc, argv, "i:f:Vh", longopts, NULL)) != -1) #else while ((c = getopt (argc, argv, "i:f:Vh")) != -1) #endif { switch (c) { case 'i': index_set = 1; set_index = atoi (optarg); break; case 'f': format = (FcChar8 *) strdup (optarg); break; case 'V': fprintf (stderr, "fontconfig version %d.%d.%d\n", FC_MAJOR, FC_MINOR, FC_REVISION); exit (0); case 'h': usage (argv[0], 0); default: usage (argv[0], 1); } } i = optind; #else i = 1; #endif if (i == argc) usage (argv[0], 1); if (!FcInit ()) { fprintf (stderr, "Can't init font config library\n"); return 1; } blanks = FcConfigGetBlanks (NULL); for (; i < argc; i++) { int index; int count = 0; index = set_index; do { FcPattern *pat; pat = FcFreeTypeQuery ((FcChar8 *) argv[i], index, blanks, &count); if (pat) { if (format) { FcChar8 *s; s = FcPatternFormat (pat, format); if (s) { printf ("%s", s); free (s); } } else { FcPatternPrint (pat); } FcPatternDestroy (pat); } else { fprintf (stderr, "Can't query face %d of font file %s\n", index, argv[i]); err = 1; } index++; } while (!index_set && index < count); } FcFini (); return err; }