]> granicus.if.org Git - libass/commitdiff
fontselect: coretext: allow to match fontname using the provider
authorStefano Pigozzi <stefano.pigozzi@gmail.com>
Sat, 2 Nov 2013 21:01:37 +0000 (22:01 +0100)
committerGrigori Goronzy <greg@chown.ath.cx>
Fri, 10 Jul 2015 08:42:40 +0000 (10:42 +0200)
Not all APIs cache everything the same way that fontconfig does. This allows
to first perform a match based on the font name and then score the matched
fonts using the common code using and in memory database approach.

The benefit is the application doesn't have to load all of the fonts and
query for weight, slant, width, path and fullnames.

I left both code paths inside ass_coretext.c. This allows to test matching
problems and have a term of comparison with the slower implementation.
To activate it one just has to flip the CT_FONTS_EAGER_LOAD define to 1.

Here are some benchmarks with a pretty typical OS X font library of ~600 fonts
and using Libass's test program to load a script with 'Helvetica Neue':

CT_FONTS_EAGER_LOAD=0
0.04s user 0.02s system 79% cpu 0.081 total

CT_FONTS_EAGER_LOAD=1
0.12s user 0.06s system 44% cpu 0.420 total

libass/ass_coretext.c
libass/ass_fontselect.c
libass/ass_types.h

index 802b511893e688fa84ca5ccf716e28f1feafacec..75a55145d4db6a7ee854b98eab3437c34ad1f5df 100644 (file)
@@ -25,6 +25,9 @@
 
 #include "ass_coretext.h"
 
+#define CT_FONTS_EAGER_LOAD 0
+#define CT_FONTS_LAZY_LOAD  !CT_FONTS_EAGER_LOAD
+
 static char *cfstr2buf(CFStringRef string)
 {
     const char *buf_ptr = CFStringGetCStringPtr(string, kCFStringEncodingUTF8);
@@ -149,15 +152,15 @@ static void get_font_traits(CTFontDescriptorRef fontd,
 #endif
 }
 
-static void scan_fonts(ASS_Library *lib, ASS_FontProvider *provider)
+static void process_descriptors(ASS_FontProvider *provider, CFArrayRef fontsd)
 {
     ASS_FontProviderMetaData meta;
     char *families[1];
     char *identifiers[1];
     char *fullnames[1];
 
-    CTFontCollectionRef coll = CTFontCollectionCreateFromAvailableFonts(NULL);
-    CFArrayRef fontsd = CTFontCollectionCreateMatchingFontDescriptors(coll);
+    if (!fontsd)
+        return;
 
     for (int i = 0; i < CFArrayGetCount(fontsd); i++) {
         CTFontDescriptorRef fontd = CFArrayGetValueAtIndex(fontsd, i);
@@ -196,16 +199,66 @@ static void scan_fonts(ASS_Library *lib, ASS_FontProvider *provider)
 
         free(path);
     }
+}
+
+#if CT_FONTS_EAGER_LOAD
+static void scan_fonts(ASS_Library *lib, ASS_FontProvider *provider)
+{
+
+    CTFontCollectionRef coll = CTFontCollectionCreateFromAvailableFonts(NULL);
+    CFArrayRef fontsd = CTFontCollectionCreateMatchingFontDescriptors(coll);
+
+    process_descriptors(provider, fontsd);
 
     CFRelease(fontsd);
     CFRelease(coll);
 }
+#endif
+
+#if CT_FONTS_LAZY_LOAD
+static void match_fonts(ASS_Library *lib, ASS_FontProvider *provider,
+                        char *name)
+{
+    void *descr_ary[1];
+
+    CFStringRef cfname =
+        CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
+    CFMutableDictionaryRef cfattrs = CFDictionaryCreateMutable(NULL, 0, 0, 0);
+    CFDictionaryAddValue(cfattrs, kCTFontDisplayNameAttribute, cfname);
+    CTFontDescriptorRef ctdescr = CTFontDescriptorCreateWithAttributes(cfattrs);
+
+    descr_ary[0] = (void *)ctdescr;
+    CFArrayRef descriptors =
+        CFArrayCreate(NULL, (const void **)&descr_ary, 1, NULL);
+
+    CTFontCollectionRef ctcoll =
+        CTFontCollectionCreateWithFontDescriptors(descriptors, 0);
+
+    CFArrayRef fontsd =
+        CTFontCollectionCreateMatchingFontDescriptors(ctcoll);
+
+    process_descriptors(provider, fontsd);
+
+    if (fontsd)
+        CFRelease(fontsd);
+    CFRelease(ctcoll);
+    CFRelease(cfattrs);
+    CFRelease(ctdescr);
+    CFRelease(descriptors);
+    CFRelease(cfname);
+}
+#endif
 
 static ASS_FontProviderFuncs coretext_callbacks = {
     NULL,
     check_glyph,
     destroy_font,
+    NULL,
+#if CT_FONTS_EAGER_LOAD
     NULL
+#else
+    match_fonts
+#endif
 };
 
 ASS_FontProvider *
@@ -214,7 +267,9 @@ ass_coretext_add_provider(ASS_Library *lib, ASS_FontSelector *selector)
     ASS_FontProvider *provider =
         ass_font_provider_new(selector, &coretext_callbacks, NULL);
 
+#if CT_FONTS_EAGER_LOAD
     scan_fonts(lib, provider);
+#endif
 
     return provider;
 }
index 799ad02d61ffc8ff9d3dd02cc66faf4e6b0f15b7..52ef192b258076799d13f164493ad113adb1383e 100644 (file)
@@ -465,9 +465,15 @@ static char *select_font(ASS_FontSelector *priv, ASS_Library *library,
 {
     int num_fonts = priv->n_font;
     int idx = 0;
-    ASS_FontInfo *font_infos = priv->font_infos;
     ASS_FontInfo req;
     char *req_fullname;
+    char *tfamily = trim_space(strdup(family));
+
+    ASS_FontProvider *default_provider = priv->default_provider;
+    if (default_provider && default_provider->funcs.match_fonts)
+        default_provider->funcs.match_fonts(library, default_provider, tfamily);
+
+    ASS_FontInfo *font_infos = priv->font_infos;
 
     // do we actually have any fonts?
     if (!priv->n_font)
@@ -480,7 +486,7 @@ static char *select_font(ASS_FontSelector *priv, ASS_Library *library,
     req.width   = 100;
     req.n_fullname   = 1;
     req.fullnames    = &req_fullname;
-    req.fullnames[0] = trim_space(strdup(family));
+    req.fullnames[0] = tfamily;
 
     // calculate similarities
     font_info_req_similarity(font_infos, num_fonts, &req);
index 16c970db1c86e5b54d1c4d7e2ea6dafd8598d7f5..e7f4ec543946093eec1d7b230e6920339e54af0c 100644 (file)
@@ -53,12 +53,16 @@ typedef size_t  (*GetDataFunc)(void *, unsigned char*, size_t, size_t);
 typedef int     (*CheckGlyphFunc)(void *, uint32_t);
 typedef void    (*DestroyFontFunc)(void *);
 typedef void    (*DestroyProviderFunc)(void *);
+typedef void    (*MatchFontsFunc)(ASS_Library *lib,
+                                  ASS_FontProvider *provider,
+                                  char *name);
 
 typedef struct font_provider_funcs {
     GetDataFunc     get_data;       // callback for memory fonts
     CheckGlyphFunc  check_glyph;    // test codepoint for coverage
     DestroyFontFunc destroy_font;   // destroy a single font
     DestroyProviderFunc destroy_provider;   // destroy provider only
+    MatchFontsFunc  match_fonts;    // match fonts against some name
     // XXX: add function for alias handling
 } ASS_FontProviderFuncs;