summaryrefslogtreecommitdiffstats
path: root/libass
diff options
context:
space:
mode:
authorStefano Pigozzi <stefano.pigozzi@gmail.com>2013-11-01 15:44:25 +0100
committerGrigori Goronzy <greg@chown.ath.cx>2015-07-10 10:42:40 +0200
commitd9585a81add0a41f6a59f3c7f95bcc6182732059 (patch)
treeb41c50287b1354a191f62497e6b5c6f16d9477e8 /libass
parentc75e58151aadc7179255d7c5c09aa61acf695d56 (diff)
downloadlibass-d9585a81add0a41f6a59f3c7f95bcc6182732059.tar.bz2
libass-d9585a81add0a41f6a59f3c7f95bcc6182732059.tar.xz
fontselect: implement a coretext font provider
Fontconfig is known to be very slow on OS X and Windows, this has to do with the extremely prohibitive cache times (which are getting even longer with latest versions of Fontconfig). This commits starts to address the problem by using CoreText on OS X to load the font data. The commit uses the simplest possible approach to load all of the data in memory and then use it to match. This causes a somewhat slow startup time (around ~400ms on my i7) but it is already better than waiting *minutes* for Fontconfig to cache the fonts data. A later commit will improve the speed of the match by using a hybrid approach that lazy loads in the libass database only the necessary fonts.
Diffstat (limited to 'libass')
-rw-r--r--libass/Makefile.am4
-rw-r--r--libass/ass_coretext.c217
-rw-r--r--libass/ass_coretext.h34
-rw-r--r--libass/ass_fontselect.c8
4 files changed, 262 insertions, 1 deletions
diff --git a/libass/Makefile.am b/libass/Makefile.am
index b8659e6..6854768 100644
--- a/libass/Makefile.am
+++ b/libass/Makefile.am
@@ -26,7 +26,9 @@ libass_la_SOURCES = ass.c ass_cache.c ass_font.c ass_fontselect.c ass_render.c \
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_fontconfig.c ass_fontconfig.h
+ ass_shaper.h ass_strtod.c ass_fontconfig.c ass_fontconfig.h \
+ ass_coretext.c ass_coretext.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_coretext.c b/libass/ass_coretext.c
new file mode 100644
index 0000000..f970226
--- /dev/null
+++ b/libass/ass_coretext.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2013 Stefano Pigozzi <stefano.pigozzi@gmail.com>
+ *
+ * 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 permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#ifdef CONFIG_CORETEXT
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreText/CoreText.h>
+
+#include "ass_coretext.h"
+
+static char *cfstr2buf(CFStringRef string)
+{
+ const char *buf_ptr = CFStringGetCStringPtr(string, kCFStringEncodingUTF8);
+ if (buf_ptr) {
+ return strdup(buf_ptr);
+ } else {
+ size_t buf_len = CFStringGetLength(string) + 1;
+ char *buf = calloc(buf_len, sizeof(char));
+ CFStringGetCString(string, buf, buf_len, kCFStringEncodingUTF8);
+ return buf;
+ }
+}
+
+static void destroy_font(void *priv)
+{
+ CFCharacterSetRef set = priv;
+ CFRelease(set);
+}
+
+static int check_glyph(void *priv, uint32_t code)
+{
+ CFCharacterSetRef set = priv;
+
+ if (!set)
+ return 1;
+
+ if (code == 0)
+ return 1;
+
+ return CFCharacterSetIsLongCharacterMember(set, code);
+}
+
+static char *get_font_file(CTFontDescriptorRef fontd)
+{
+ CFURLRef url = CTFontDescriptorCopyAttribute(fontd, kCTFontURLAttribute);
+ CFStringRef path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
+ char *buffer = cfstr2buf(path);
+ CFRelease(path);
+ CFRelease(url);
+ return buffer;
+}
+
+static void get_name(CTFontDescriptorRef fontd, CFStringRef attr,
+ char **array, int *idx)
+{
+
+ CFStringRef name = CTFontDescriptorCopyAttribute(fontd, attr);
+ if (name) {
+ array[*idx] = cfstr2buf(name);
+ CFRelease(name);
+ *idx += 1;
+ }
+}
+
+static void get_trait(CFDictionaryRef traits, CFStringRef attribute,
+ float *trait)
+{
+ CFNumberRef cftrait = CFDictionaryGetValue(traits, attribute);
+ if (!CFNumberGetValue(cftrait, kCFNumberFloatType, trait))
+ *trait = 0.0;
+}
+
+static void get_font_traits(CTFontDescriptorRef fontd,
+ ASS_FontProviderMetaData *meta)
+{
+ float weight, slant, width;
+
+ CFDictionaryRef traits =
+ CTFontDescriptorCopyAttribute(fontd, kCTFontTraitsAttribute);
+
+ get_trait(traits, kCTFontWeightTrait, &weight);
+ get_trait(traits, kCTFontSlantTrait, &slant);
+ get_trait(traits, kCTFontWidthTrait, &width);
+
+ CFRelease(traits);
+
+ // Printed all of my system fonts (see if'deffed code below). Here is how
+ // CoreText 'normalized' weights maps to CSS/libass:
+
+ // opentype: 0 100 200 300 400 500 600 700 800 900
+ // css: LIGHT REG MED SBOLD BOLD BLACK EXTRABL
+ // libass: LIGHT MEDIUM BOLD
+ // coretext: -0.4 0.0 0.23 0.3 0.4 0.62
+
+ if (weight >= 0.62)
+ meta->weight = 800;
+ else if (weight >= 0.4)
+ meta->weight = 700;
+ else if (weight >= 0.3)
+ meta->weight = 600;
+ else if (weight >= 0.23)
+ meta->weight = 500;
+ else if (weight >= -0.4)
+ meta->weight = 400;
+ else
+ meta->weight = 200;
+
+ if (slant > 0.03)
+ meta->slant = FONT_SLANT_ITALIC;
+ else
+ meta->slant = FONT_SLANT_NONE;
+
+ if (width <= -0.2)
+ meta->width = FONT_WIDTH_CONDENSED;
+ else if (width >= 0.2)
+ meta->width = FONT_WIDTH_EXPANDED;
+ else
+ meta->width = FONT_WIDTH_NORMAL;
+
+#if 0
+ char *name[1];
+ int idx = 0;
+ get_name(fontd, kCTFontDisplayNameAttribute, name, &idx);
+ char *file = get_font_file(fontd);
+ printf(
+ "Font traits for: %-40s [%-50s] "
+ "<slant: %f, %03d>, <weight: (%f, %03d)>, <width: %f, %03d>\n",
+ name[0], file,
+ slant, meta->slant, weight, meta->weight, width, meta->width);
+ free(name[0]);
+ free(file);
+#endif
+}
+
+static void scan_fonts(ASS_Library *lib, ASS_FontProvider *provider)
+{
+ ASS_FontProviderMetaData meta;
+ char *families[1];
+ char *fullnames[2];
+
+ CTFontCollectionRef coll = CTFontCollectionCreateFromAvailableFonts(NULL);
+ CFArrayRef fontsd = CTFontCollectionCreateMatchingFontDescriptors(coll);
+
+ for (int i = 0; i < CFArrayGetCount(fontsd); i++) {
+ CTFontDescriptorRef fontd = CFArrayGetValueAtIndex(fontsd, i);
+ int index = 0;
+
+ char *path = get_font_file(fontd);
+ if (strcmp("", path) == 0) {
+ // skip the font if the URL field in the font descriptor is empty
+ free(path);
+ continue;
+ }
+
+ memset(&meta, 0, sizeof(meta));
+ get_font_traits(fontd, &meta);
+
+ get_name(fontd, kCTFontFamilyNameAttribute, families, &meta.n_family);
+ meta.families = families;
+
+ get_name(fontd, kCTFontDisplayNameAttribute, fullnames, &meta.n_fullname);
+ get_name(fontd, kCTFontNameAttribute, fullnames, &meta.n_fullname);
+ meta.fullnames = fullnames;
+
+ CFCharacterSetRef chset =
+ CTFontDescriptorCopyAttribute(fontd, kCTFontCharacterSetAttribute);
+ ass_font_provider_add_font(provider, &meta, path, index, (void*)chset);
+
+ for (int j = 0; j < meta.n_family; j++)
+ free(meta.families[j]);
+
+ for (int j = 0; j < meta.n_fullname; j++)
+ free(meta.fullnames[j]);
+
+ free(path);
+ }
+
+ CFRelease(fontsd);
+ CFRelease(coll);
+}
+
+static ASS_FontProviderFuncs coretext_callbacks = {
+ NULL,
+ check_glyph,
+ destroy_font,
+ NULL
+};
+
+ASS_FontProvider *
+ass_coretext_add_provider(ASS_Library *lib, ASS_FontSelector *selector)
+{
+ ASS_FontProvider *provider =
+ ass_font_provider_new(selector, &coretext_callbacks, NULL);
+
+ scan_fonts(lib, provider);
+
+ return provider;
+}
+
+#endif
diff --git a/libass/ass_coretext.h b/libass/ass_coretext.h
new file mode 100644
index 0000000..8d96927
--- /dev/null
+++ b/libass/ass_coretext.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2013 Stefano Pigozzi <stefano.pigozzi@gmail.com>
+ *
+ * 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 permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include "ass_types.h"
+#include "ass_fontselect.h"
+
+#ifndef ASS_CORETEXT_H
+#define ASS_CORETEXT_H
+
+#ifdef CONFIG_CORETEXT
+
+ASS_FontProvider *
+ass_coretext_add_provider(ASS_Library *lib, ASS_FontSelector *selector);
+
+#endif
+
+#endif
diff --git a/libass/ass_fontselect.c b/libass/ass_fontselect.c
index cf1c088..9ef0ace 100644
--- a/libass/ass_fontselect.c
+++ b/libass/ass_fontselect.c
@@ -37,6 +37,7 @@
#include "ass_library.h"
#include "ass_fontselect.h"
#include "ass_fontconfig.h"
+#include "ass_coretext.h"
#include "ass_font.h"
#define ABS(x) ((x) < 0 ? -(x) : (x))
@@ -803,6 +804,13 @@ ass_fontselect_init(ASS_Library *library,
priv->embedded_provider = ass_embedded_fonts_add_provider(library, priv,
ftlibrary);
+#ifdef CONFIG_CORETEXT
+ if (fc != 0) {
+ priv->default_provider = ass_coretext_add_provider(library, priv);
+ return priv;
+ }
+#endif
+
#ifdef CONFIG_FONTCONFIG
if (fc != 0)
priv->default_provider = ass_fontconfig_add_provider(library,