@@ 0,0 1,651 @@
+#include "transcode.h"
+#include <fontconfig/fontconfig.h>
+#include <stdlib.h>
+#include <fontconfig/fcfreetype.h>
+
+uint8_t *fcNameParse(char *name, size_t *length) {
+ FcPattern *pat = FcNameParse(name);
+ if (pat == NULL) return NULL;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) {FcPatternDestroy(pat); return NULL;}
+ if (!encodePattern(&out, pat)) {
+ FcPatternDestroy(pat); cmp_bytes_free(&out); return NULL;
+ }
+ FcPatternDestroy(pat);
+ return cmp_bytes_take(&out, length);
+}
+
+char *fcNameUnparse(uint8_t *data, size_t length) {
+ cmp_ctx_t in;
+ if (!cmp_bytes_init(&in, data, length)) return NULL;
+ FcPattern *pat = decodePattern(&in);
+ cmp_bytes_take(&in, NULL); // Caller frees `data`!
+ if (pat == NULL) return NULL;
+
+ char *ret = FcNameUnparse(pat);
+ FcPatternDestroy(pat);
+ return ret;
+}
+
+char *fcNameFormat(uint8_t *data, size_t length, char *format) {
+ cmp_ctx_t in;
+ if (!cmp_bytes_init(&in, data, length)) return NULL;
+ FcPattern *pat = decodePattern(&in);
+ cmp_bytes_take(&in, NULL); // Caller frees `data`!
+ if (pat == NULL) return NULL;
+
+ char *ret = FcPatternFormat(pat, format);
+ FcPatternDestroy(pat);
+ return ret;
+}
+
+uint8_t *fcFontSetList(FcConfig *config, uint8_t *sets, size_t sets_length,
+ uint8_t *pat, size_t pat_length, uint8_t *objects, size_t objs_length, size_t *length) {
+ cmp_ctx_t in;
+ uint8_t *ret = NULL;
+
+ if (!cmp_bytes_init(&in, sets, sets_length)) return NULL;
+ size_t nsets;
+ FcFontSet **fontsets = decodeFontSets(&in, &nsets);
+ cmp_bytes_take(&in, NULL);
+ if (fontsets == NULL) return NULL;
+
+ if (!cmp_bytes_init(&in, pat, pat_length)) goto fail_pat;
+ FcPattern *pattern = decodePattern(&in);
+ cmp_bytes_take(&in, NULL);
+ if (pattern == NULL) goto fail_pat;
+
+ if (!cmp_bytes_init(&in, objects, objs_length)) goto fail_objs;
+ FcObjectSet *objs = decodeObjectSet(&in);
+ cmp_bytes_take(&in, NULL);
+ if (objs == NULL) goto fail_objs;
+
+ FcFontSet *res = FcFontSetList(config, fontsets, nsets, pattern, objs);
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) goto fail;
+ bool ok = encodeFontSet(&out, res);
+ ret = cmp_bytes_take(&out, length);
+ if (!ok && ret != NULL) { free(ret); ret = NULL;}
+
+fail:
+ FcFontSetDestroy(res);
+ FcObjectSetDestroy(objs);
+fail_objs:
+ FcPatternDestroy(pattern);
+fail_pat:
+ for (size_t i = 0; i < nsets; i++) FcFontSetDestroy(fontsets[i]);
+ free(fontsets);
+ return ret;
+}
+
+
+// FcResultMatch, FcResultNoMatch, FcResultTypeMismatch, FcResultNoId, FcResultOutOfMemory
+
+uint8_t *fcFontSetMatch(FcConfig *config, uint8_t *sets, size_t sets_length,
+ uint8_t *pat, size_t pat_length, size_t *length) {
+ cmp_ctx_t in;
+ uint8_t *ret = NULL;
+
+ if (!cmp_bytes_init(&in, sets, sets_length)) return NULL;
+ size_t nsets;
+ FcFontSet **fontsets = decodeFontSets(&in, &nsets);
+ cmp_bytes_take(&in, NULL);
+ if (fontsets == NULL) return NULL;
+
+ if (!cmp_bytes_init(&in, pat, pat_length)) goto fail;
+ FcPattern *pattern = decodePattern(&in);
+ cmp_bytes_take(&in, NULL);
+ if (pattern == NULL) goto fail;
+
+ // Necessary preprocessing!
+ FcPattern *res = NULL;
+ if (!FcConfigSubstitute(config, pattern, FcMatchPattern)) goto fail2;
+ FcDefaultSubstitute(pattern);
+
+ FcResult err;
+ res = FcFontSetMatch(config, fontsets, nsets, pattern, &err);
+
+ cmp_ctx_t out;
+ bool ok;
+ if (err == FcResultMatch) {
+ if (!cmp_bytes_alloc(&out, 1024)) goto fail2;
+ ok = encodePattern(&out, res);
+ ret = cmp_bytes_take(&out, length);
+ if (!ok && ret != NULL) { free(ret); ret = NULL; }
+ } else {
+ if (!cmp_bytes_alloc(&out, 32)) goto fail2;
+ ok = encodeResult(&out, err);
+ ret = cmp_bytes_take(&out, length);
+ if (!ok && ret != NULL) { free(ret); ret = NULL; }
+ }
+
+fail2:
+ if (res != NULL) FcPatternDestroy(res);
+ FcPatternDestroy(pattern);
+fail:
+ for (size_t i = 0; i < nsets; i++) FcFontSetDestroy(fontsets[i]);
+ free(fontsets);
+ return ret;
+}
+
+uint8_t *fcFontSetSort(FcConfig *config, uint8_t *sets, size_t sets_length,
+ uint8_t *pat, size_t pat_length, bool trim, size_t *length) {
+ cmp_ctx_t in;
+ uint8_t *ret = NULL;
+
+ if (!cmp_bytes_init(&in, sets, sets_length)) return NULL;
+ size_t nsets;
+ FcFontSet **fontsets = decodeFontSets(&in, &nsets);
+ cmp_bytes_take(&in, NULL);
+ if (fontsets == NULL) return NULL;
+
+ if (!cmp_bytes_init(&in, pat, pat_length)) goto fail;
+ FcPattern *pattern = decodePattern(&in);
+ cmp_bytes_take(&in, NULL);
+ if (pattern == NULL) goto fail;
+
+ // Necessary preprocessing!
+ if (!FcConfigSubstitute(config, pattern, FcMatchPattern)) goto fail2;
+ FcDefaultSubstitute(pattern);
+
+ FcResult err;
+ FcCharSet *charset = NULL;
+ FcFontSet *res = FcFontSetSort(config, fontsets, nsets, pattern, trim, &charset, &err);
+
+ cmp_ctx_t out;
+ bool ok = true;
+ switch (err) {
+ case FcResultMatch:
+ if (!cmp_bytes_alloc(&out, 1024*res->nfont)) goto fail3;
+ ok = ok || cmp_write_array(&out, 2);
+ if (res == NULL) cmp_write_nil(&out);
+ else {
+ // FIXME: Postprocess each font! Rather than call encodeFontSet!
+ ok = ok || encodeFontSet(&out, res);
+ }
+ if (charset == NULL) cmp_write_nil(&out);
+ else ok = ok || encodeCharSet(&out, charset);
+ break;
+ case FcResultNoMatch:
+ if (!cmp_bytes_alloc(&out, 1024)) goto fail3;
+ ok = ok || cmp_write_array(&out, 2);
+ ok = ok || cmp_write_array(&out, 0);
+ if (charset == NULL) cmp_write_nil(&out);
+ else ok = ok || encodeCharSet(&out, charset);
+ break;
+ default:
+ if (!cmp_bytes_alloc(&out, 32)) goto fail3;
+ ok = ok || encodeResult(&out, err);
+ }
+ ret = cmp_bytes_take(&out, length);
+ if (!ok && ret != NULL) { free(ret); ret = NULL; }
+
+fail3:
+ FcFontSetDestroy(res);
+ if (charset != NULL) FcCharSetDestroy(charset);
+fail2:
+ FcPatternDestroy(pattern);
+fail:
+ for (size_t i = 0; i < nsets; i++) FcFontSetDestroy(fontsets[i]);
+ free(fontsets);
+ return ret;
+}
+
+unsigned int fcFreeTypeCharIndex(FT_Face *face, uint32_t ucs4) {
+ return FcFreeTypeCharIndex(*face, ucs4);
+}
+
+uint8_t *fcFreeTypeCharSet(FT_Face *face, size_t *length) {
+ FcCharSet *res = FcFreeTypeCharSet(*face, NULL);
+
+ if (res == NULL) return NULL;
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) {
+ FcCharSetDestroy(res);
+ return NULL;
+ }
+ if (!encodeCharSet(&out, res)) {
+ FcCharSetDestroy(res);
+ cmp_bytes_free(&out);
+ return NULL;
+ }
+ FcCharSetDestroy(res);
+ return cmp_bytes_take(&out, length);;
+}
+
+uint8_t *fcFreeTypeCharSetAndSpacing(FT_Face *face, size_t *length) {
+ int spacing;
+ FcCharSet *res = FcFreeTypeCharSetAndSpacing(*face, NULL, &spacing);
+ if (res == NULL) return NULL;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) {
+ FcCharSetDestroy(res);
+ return NULL;
+ }
+ if (!cmp_write_array(&out, 2)) goto fail;
+ switch (spacing) { // This branches ensures a consistant ABI for Haskell to bind against.
+ case FC_MONO:
+ if (!cmp_write_integer(&out, 0)) goto fail;
+ break;
+ case FC_DUAL:
+ if (!cmp_write_integer(&out, 1)) goto fail;
+ break;
+ case FC_PROPORTIONAL:
+ if (!cmp_write_integer(&out, 2)) goto fail;
+ break;
+ default:
+ if (!cmp_write_integer(&out, 3)) goto fail;
+ break;
+ }
+ if (!encodeCharSet(&out, res)) goto fail;
+ FcCharSetDestroy(res);
+ return cmp_bytes_take(&out, length);;
+
+fail:
+ FcCharSetDestroy(res);
+ cmp_bytes_free(&out);
+ return NULL;
+}
+
+uint8_t *fcFreeTypeQuery(char *file, int id, size_t *length) {
+ int count;
+ FcPattern *res = FcFreeTypeQuery(file, id, NULL, &count);
+ if (res == NULL) return NULL;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) {
+ FcPatternDestroy(res);
+ return NULL;
+ }
+ if (!cmp_write_array(&out, 2)) goto fail;
+ if (!cmp_write_integer(&out, count)) goto fail;
+ if (!encodePattern(&out, res)) goto fail;
+ FcPatternDestroy(res);
+ return cmp_bytes_take(&out, length);;
+
+fail:
+ FcPatternDestroy(res);
+ cmp_bytes_free(&out);
+ return NULL;
+}
+
+uint8_t *fcFreeTypeQueryAll(char *file, size_t *length) {
+ int count;
+ FcFontSet *fontset = FcFontSetCreate();
+ if (fontset == NULL) return NULL;
+ unsigned int npatterns = FcFreeTypeQueryAll(file, -1, NULL, &count, fontset);
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) {
+ FcFontSetDestroy(fontset);
+ return NULL;
+ }
+ if (!cmp_write_array(&out, 3)) goto fail;
+ if (!cmp_write_integer(&out, npatterns)) goto fail;
+ if (!cmp_write_integer(&out, count)) goto fail;
+ if (!encodeFontSet(&out, fontset)) goto fail;
+ uint8_t *ret = cmp_bytes_take(&out, length);
+ FcFontSetDestroy(fontset);
+ return ret;
+
+fail:
+ FcFontSetDestroy(fontset);
+ cmp_bytes_free(&out);
+ return NULL;
+}
+
+uint8_t *fcFreeTypeQueryFace(FT_Face *face, char *file, int id, size_t *length) {
+ FcPattern *res = FcFreeTypeQueryFace(*face, file, id, NULL);
+ if (res == NULL) return NULL;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) {
+ FcPatternDestroy(res);
+ return NULL;
+ }
+ if (!encodePattern(&out, res)) {
+ FcPatternDestroy(res);
+ cmp_bytes_free(&out);
+ }
+ uint8_t *ret = cmp_bytes_take(&out, length);
+ FcPatternDestroy(res);
+ return ret;
+}
+
+int fcLangSetHasLang(uint8_t *langset, size_t length, const char *lang) {
+ cmp_ctx_t in;
+ if (!cmp_bytes_init(&in, langset, length)) return -1;
+ FcLangSet *ls = decodeLangSet(&in);
+ cmp_bytes_take(&in, NULL); // Caller frees `langset`
+ if (ls == NULL) return -1;
+
+ FcLangResult ret = FcLangSetHasLang(ls, lang);
+ FcLangSetDestroy(ls);
+ switch (ret) {
+ case FcLangDifferentLang:
+ return 0;
+ case FcLangEqual:
+ return 1;
+ case FcLangDifferentTerritory:
+ return 2;
+ default:
+ return -2;
+ }
+}
+
+uint8_t *fcGetDefaultLangs(size_t *length) {
+ FcStrSet *res = FcGetDefaultLangs();
+ if (res == NULL) return NULL;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) {
+ FcStrSetDestroy(res);
+ return NULL;
+ }
+ if (!encodeStrSet(&out, res)) {
+ cmp_bytes_free(&out);
+ FcStrSetDestroy(res);
+ return NULL;
+ }
+ FcStrSetDestroy(res);
+ return cmp_bytes_take(&out, length);
+}
+
+uint8_t *fcGetLangs(size_t *length) {
+ FcStrSet *res = FcGetLangs();
+ if (res == NULL) return NULL;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) {
+ FcStrSetDestroy(res);
+ return NULL;
+ }
+ if (!encodeStrSet(&out, res)) {
+ cmp_bytes_free(&out);
+ FcStrSetDestroy(res);
+ return NULL;
+ }
+ FcStrSetDestroy(res);
+ return cmp_bytes_take(&out, length);
+}
+
+char *fcLangNormalize(char *lang) {return FcLangNormalize(lang);}
+
+uint8_t *fcLangGetCharSet(const char *lang, size_t *length) {
+ const FcCharSet *res = FcLangGetCharSet(lang);
+ if (res == NULL) return NULL;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) return NULL;
+ if (!encodeCharSet(&out, res)) {
+ cmp_bytes_free(&out);
+ return NULL;
+ }
+ return cmp_bytes_take(&out, length);
+}
+
+uint8_t *fcConfigGetConfigDirs(FcConfig *conf, size_t *length) {
+ FcStrList *res = FcConfigGetConfigDirs(conf);
+ if (res == NULL) return NULL;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) {
+ FcStrListDone(res);
+ return NULL;
+ }
+ if (!encodeStrList(&out, res)) {
+ cmp_bytes_free(&out);
+ FcStrListDone(res);
+ return NULL;
+ }
+ FcStrListDone(res);
+ return cmp_bytes_take(&out, length);
+}
+
+uint8_t *fcConfigGetFontDirs(FcConfig *conf, size_t *length) {
+ FcStrList *res = FcConfigGetFontDirs(conf);
+ if (res == NULL) return NULL;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) {
+ FcStrListDone(res);
+ return NULL;
+ }
+ if (!encodeStrList(&out, res)) {
+ cmp_bytes_free(&out);
+ FcStrListDone(res);
+ return NULL;
+ }
+ FcStrListDone(res);
+ return cmp_bytes_take(&out, length);
+}
+
+uint8_t *fcConfigGetConfigFiles(FcConfig *conf, size_t *length) {
+ FcStrList *res = FcConfigGetConfigFiles(conf);
+ if (res == NULL) return NULL;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) {
+ FcStrListDone(res);
+ return NULL;
+ }
+ if (!encodeStrList(&out, res)) {
+ cmp_bytes_free(&out);
+ FcStrListDone(res);
+ return NULL;
+ }
+ FcStrListDone(res);
+ return cmp_bytes_take(&out, length);
+}
+
+uint8_t *fcConfigGetCacheDirs(FcConfig *conf, size_t *length) {
+ FcStrList *res = FcConfigGetCacheDirs(conf);
+ if (res == NULL) return NULL;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) {
+ FcStrListDone(res);
+ return NULL;
+ }
+ if (!encodeStrList(&out, res)) {
+ cmp_bytes_free(&out);
+ FcStrListDone(res);
+ return NULL;
+ }
+ FcStrListDone(res);
+ return cmp_bytes_take(&out, length);
+}
+
+uint8_t *fcConfigGetFonts(FcConfig *conf, bool system, size_t *length) {
+ FcFontSet *res = FcConfigGetFonts(conf, system ? FcSetSystem : FcSetApplication);
+ if (res == NULL) return NULL;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) {
+ FcFontSetDestroy(res);
+ return NULL;
+ }
+ if (!encodeFontSet(&out, res)) {
+ cmp_bytes_free(&out);
+ FcFontSetDestroy(res);
+ return NULL;
+ }
+ FcFontSetDestroy(res);
+ return cmp_bytes_take(&out, length);
+}
+
+uint8_t *fcConfigSubstituteWithPat(FcConfig *conf, uint8_t *data, size_t in_length, bool isFont, size_t *length) {
+ cmp_ctx_t in;
+ if (!cmp_bytes_init(&in, data, in_length)) return NULL;
+
+ uint32_t size = 0;
+ if (!cmp_read_array(&in, &size) || size < 1 || size > 2) return NULL;
+ FcPattern *p = decodePattern(&in);
+ if (p == NULL) {cmp_bytes_take(&in, NULL); return NULL;}
+ FcPattern *p_pat = NULL;
+ if (size == 2) {
+ p_pat = decodePattern(&in);
+ if (p_pat == NULL) {cmp_bytes_take(&in, NULL); goto fail;}
+ }
+ cmp_bytes_take(&in, NULL);
+
+ if (!FcConfigSubstituteWithPat(conf, p, p_pat, isFont ? FcMatchFont : FcMatchPattern)) goto fail;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) goto fail;
+ if (!encodePattern(&out, p)) goto fail;
+ FcPatternDestroy(p);
+ if (p_pat != NULL) FcPatternDestroy(p_pat);
+ return cmp_bytes_take(&out, length);
+
+fail:
+ FcPatternDestroy(p);
+ if (p_pat != NULL) FcPatternDestroy(p_pat);
+ return NULL;
+}
+
+uint8_t *fcFontMatch(FcConfig *conf, uint8_t *data, size_t in_length, size_t *length) {
+ cmp_ctx_t in;
+ if (!cmp_bytes_init(&in, data, in_length)) return NULL;
+ FcPattern *p = decodePattern(&in);
+ cmp_bytes_take(&in, NULL);
+ if (p == NULL) return NULL;
+
+ if (!FcConfigSubstitute(conf, p, FcMatchPattern)) goto fail;
+ FcDefaultSubstitute(p);
+
+ FcResult err;
+ FcPattern *res = FcFontMatch(conf, p, &err);
+ if (res == NULL) goto fail;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) goto fail;
+ if (err != FcResultMatch) {
+ if (!encodeResult(&out, err)) goto fail2;
+ } else {
+ if (!encodePattern(&out, res)) goto fail2;
+ }
+ FcPatternDestroy(p);
+ return cmp_bytes_take(&out, length);;
+
+fail2:
+ cmp_bytes_free(&out);
+fail:
+ FcPatternDestroy(p);
+ return NULL;
+}
+
+uint8_t *fcFontSort(FcConfig *conf, uint8_t *data, size_t in_length, bool trim, size_t *length) {
+ cmp_ctx_t in;
+ if (!cmp_bytes_init(&in, data, in_length)) return NULL;
+ FcPattern *p = decodePattern(&in);
+ cmp_bytes_take(&in, NULL);
+ if (p == NULL) return NULL;
+
+ if (!FcConfigSubstitute(conf, p, FcMatchPattern)) goto fail;
+ FcDefaultSubstitute(p);
+
+ FcResult err;
+ FcCharSet *csp;
+ FcFontSet *res = FcFontSort(conf, p, trim, &csp, &err);
+ if (res == NULL) goto fail2;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) goto fail2;
+ if (err != FcResultMatch) {
+ if (!encodeResult(&out, err)) goto fail3;
+ } else if (csp != NULL) {
+ if (!cmp_write_array(&out, 2)) goto fail3;
+ if (!encodeFontSet(&out, res)) goto fail3;
+ if (!encodeCharSet(&out, csp)) goto fail3;
+ } else {
+ if (!cmp_write_array(&out, 1)) goto fail3;
+ if (!encodeFontSet(&out, res)) goto fail3;
+ }
+ FcPatternDestroy(p);
+ if (csp != NULL) FcCharSetDestroy(csp);
+ return cmp_bytes_take(&out, length);
+
+fail3:
+ cmp_bytes_free(&out);
+fail2:
+ if (csp != NULL) FcCharSetDestroy(csp);
+fail:
+ FcPatternDestroy(p);
+ return NULL;
+}
+
+uint8_t *fcFontRenderPrepare(FcConfig *conf, uint8_t *data, size_t in_length, size_t *length) {
+ cmp_ctx_t in;
+ if (!cmp_bytes_init(&in, data, in_length)) return NULL;
+ uint32_t size = 0;
+ if (!cmp_read_array(&in, &size) || size != 2) return NULL;
+ FcPattern *pat = decodePattern(&in);
+ if (pat == NULL) {cmp_bytes_take(&in, NULL); return NULL;}
+ FcPattern *font = decodePattern(&in);
+ cmp_bytes_take(&in, NULL);
+ if (font == NULL) {FcPatternDestroy(pat); return NULL; }
+
+ FcPattern *res = FcFontRenderPrepare(conf, pat, font);
+ if (res == NULL) goto fail0;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) goto fail;
+ if (!encodePattern(&out, res)) {cmp_bytes_free(&out); goto fail;}
+ FcPatternDestroy(pat);
+ FcPatternDestroy(font);
+ FcPatternDestroy(res);
+ return cmp_bytes_take(&out, length);
+
+fail:
+ FcPatternDestroy(res);
+fail0:
+ FcPatternDestroy(pat);
+ FcPatternDestroy(font);
+ return NULL;
+}
+
+uint8_t *fcFontList(FcConfig *conf, uint8_t *data, size_t in_length, size_t *length) {
+ cmp_ctx_t in;
+ if (!cmp_bytes_init(&in, data, in_length)) return NULL;
+ uint32_t size = 0;
+ if (!cmp_read_array(&in, &size) || size != 2) {
+ cmp_bytes_take(&in, NULL);
+ return NULL;
+ }
+ FcPattern *pat = decodePattern(&in);
+ if (pat == NULL) {cmp_bytes_take(&in, NULL); return NULL;}
+ FcObjectSet *os = decodeObjectSet(&in);
+ cmp_bytes_take(&in, NULL);
+ if (os == NULL) {FcPatternDestroy(pat); return NULL;}
+
+ FcFontSet *res = FcFontList(conf, pat, os);
+ if (res == NULL) goto fail0;
+
+ cmp_ctx_t out;
+ if (!cmp_bytes_alloc(&out, 1024)) goto fail;
+ if (!encodeFontSet(&out, res)) { cmp_bytes_free(&out); goto fail;}
+ FcFontSetDestroy(res);
+ return cmp_bytes_take(&out, length);
+
+fail:
+ FcFontSetDestroy(res);
+fail0:
+ FcPatternDestroy(pat);
+ FcObjectSetDestroy(os);
+ return NULL;
+}
+
+/*int fcConfigAcceptFont(FcConfig *conf, uint8_t *data, size_t length) {
+ cmp_ctx_t in;
+ if (!cmp_bytes_init(&in, data, length)) return -1;
+ FcPattern *pat = decodePattern(&in);
+ if (pat == NULL) return -1;
+
+ FcBool ret = FcConfigAcceptFont(conf, pat);
+ FcPatternDestroy(pat);
+ return ret ? 1 : 0;
+}*/