summaryrefslogtreecommitdiffstats
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
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.
-rw-r--r--configure.ac22
-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
5 files changed, 284 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac
index fce38ef..6cfd823 100644
--- a/configure.ac
+++ b/configure.ac
@@ -151,6 +151,28 @@ PKG_CHECK_MODULES([FONTCONFIG], fontconfig >= 2.4.2, [
])
fi
+if test x$enable_coretext != xno; then
+OLDLIBS="$LIBS"
+# Linking to CoreText directly only works from Mountain Lion and iOS6. In
+# earlier OS releases CoreText was part of the ApplicationServices umbrella
+# framework.
+LIBS="$LIBS -framework CoreText -framework CoreFoundation -framework CoreGraphics"
+AC_MSG_CHECKING([for CORETEXT])
+AC_LINK_IFELSE([
+ AC_LANG_PROGRAM(
+ [[#include <CoreText/CoreText.h>]],
+ [[CTFontCreateWithFontDescriptor(NULL, 0.0, NULL);]],)
+ ], [
+ AC_DEFINE(CONFIG_CORETEXT, 1, [found CoreText in System library])
+ coretext=true
+ AC_MSG_RESULT([yes])
+ ], [
+ LIBS="$OLDLIBS"
+ coretext=false
+ AC_MSG_RESULT([no])
+ ])
+fi
+
if test x$enable_harfbuzz != xno; then
PKG_CHECK_MODULES([HARFBUZZ], harfbuzz >= 0.9.5, [
CFLAGS="$CFLAGS $HARFBUZZ_CFLAGS"
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,