diff options
-rw-r--r-- | configure.ac | 67 | ||||
-rw-r--r-- | libass/Makefile.am | 19 | ||||
-rw-r--r-- | libass/ass.c | 2 | ||||
-rw-r--r-- | libass/ass.h | 47 | ||||
-rw-r--r-- | libass/ass_cache.c | 4 | ||||
-rw-r--r-- | libass/ass_coretext.c | 295 | ||||
-rw-r--r-- | libass/ass_coretext.h | 35 | ||||
-rw-r--r-- | libass/ass_directwrite.c | 715 | ||||
-rw-r--r-- | libass/ass_directwrite.h | 31 | ||||
-rw-r--r-- | libass/ass_font.c | 131 | ||||
-rw-r--r-- | libass/ass_font.h | 28 | ||||
-rw-r--r-- | libass/ass_fontconfig.c | 705 | ||||
-rw-r--r-- | libass/ass_fontconfig.h | 32 | ||||
-rw-r--r-- | libass/ass_fontselect.c | 1043 | ||||
-rw-r--r-- | libass/ass_fontselect.h | 260 | ||||
-rw-r--r-- | libass/ass_library.h | 2 | ||||
-rw-r--r-- | libass/ass_parse.c | 11 | ||||
-rw-r--r-- | libass/ass_render.c | 13 | ||||
-rw-r--r-- | libass/ass_render.h | 4 | ||||
-rw-r--r-- | libass/ass_render_api.c | 25 | ||||
-rw-r--r-- | libass/ass_shaper.c | 2 | ||||
-rw-r--r-- | libass/ass_types.h | 13 | ||||
-rw-r--r-- | libass/ass_utils.c | 26 | ||||
-rw-r--r-- | libass/ass_utils.h | 6 | ||||
-rw-r--r-- | libass/dwrite_c.h | 673 | ||||
-rw-r--r-- | libass/libass.sym | 1 | ||||
-rw-r--r-- | test/test.c | 27 |
27 files changed, 3602 insertions, 615 deletions
diff --git a/configure.ac b/configure.ac index fce38ef..ba0f5e0 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,7 @@ AC_INIT(libass, 0.12.3) AM_INIT_AUTOMAKE AC_CONFIG_MACRO_DIR([m4]) -# Disable C++/Fortran checks -define([AC_LIBTOOL_LANG_CXX_CONFIG], [:]) +# Disable Fortran checks define([AC_LIBTOOL_LANG_F77_CONFIG], [:]) LT_INIT AC_CONFIG_SRCDIR([libass/ass.c]) @@ -17,20 +16,13 @@ AM_PROG_AS # Checks for header files. AC_HEADER_STDC AC_HEADER_STDBOOL -AC_CHECK_HEADERS([inttypes.h stdint.h stdlib.h string.h sys/time.h unistd.h iconv.h]) - -# Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_C_INLINE -AC_TYPE_INT64_T -AC_TYPE_SIZE_T -AC_TYPE_UINT32_T -AC_TYPE_UINT8_T +AC_CHECK_HEADERS([stdint.h unistd.h iconv.h]) # Checks for library functions. -AC_CHECK_FUNCS([mkdir strcasecmp strdup strndup strtol]) +AC_CHECK_FUNCS([strdup strndup]) # Checks for libraries. +AC_SEARCH_LIBS([libiconv_open], [iconv], AC_DEFINE(CONFIG_ICONV, 1, [use iconv])) AC_SEARCH_LIBS([iconv_open], [iconv], AC_DEFINE(CONFIG_ICONV, 1, [use iconv])) AC_CHECK_LIB([m], [fabs]) @@ -43,6 +35,10 @@ AC_ARG_ENABLE([enca], AS_HELP_STRING([--disable-enca], [disable enca (charset autodetect) support @<:@default=check@:>@])) AC_ARG_ENABLE([fontconfig], AS_HELP_STRING([--disable-fontconfig], [disable fontconfig support @<:@default=enabled@:>@])) +AC_ARG_ENABLE([directwrite], AS_HELP_STRING([--disable-directwrite], + [disable DirectWrite support (win32 only) @<:@default=check@:>@])) +AC_ARG_ENABLE([coretext], AS_HELP_STRING([--disable-coretext], + [disable CoreText support (OSX only) @<:@default=check@:>@])) AC_ARG_ENABLE([harfbuzz], AS_HELP_STRING([--disable-harfbuzz], [disable HarfBuzz support @<:@default=check@:>@])) AC_ARG_ENABLE([asm], AS_HELP_STRING([--disable-asm], @@ -132,6 +128,7 @@ AM_COND_IF([ENABLE_LARGE_TILES], PKG_CHECK_MODULES([FREETYPE], freetype2 >= 9.10.3, [ CFLAGS="$CFLAGS $FREETYPE_CFLAGS" + CXXFLAGS="$CFLAGS $FREETYPE_CFLAGS" LIBS="$LIBS $FREETYPE_LIBS" AC_DEFINE(CONFIG_FREETYPE, 1, [found freetype2 via pkg-config]) ]) @@ -151,6 +148,49 @@ 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 +AM_CONDITIONAL([CORETEXT], [test x$coretext = xtrue]) + + + +if test x$enable_directwrite != xno; then +# Linking to DirectWrite directly only works from Windows +AC_MSG_CHECKING([for DIRECTWRITE]) +AC_LINK_IFELSE([ + AC_LANG_PROGRAM( + [[#include <windows.h>]], + [[;]],) + ], [ + AC_DEFINE(CONFIG_DIRECTWRITE, 1, [found DirectWrite]) + directwrite=true + AC_MSG_RESULT([yes]) + ], [ + directwrite=false + AC_MSG_RESULT([no]) + ]) +fi +AM_CONDITIONAL([DIRECTWRITE], [test x$directwrite = xtrue]) + if test x$enable_harfbuzz != xno; then PKG_CHECK_MODULES([HARFBUZZ], harfbuzz >= 0.9.5, [ CFLAGS="$CFLAGS $HARFBUZZ_CFLAGS" @@ -194,6 +234,9 @@ fi if test x$harfbuzz = xtrue; then pkg_requires="harfbuzz >= 0.9.5, ${pkg_requires}" fi +if test x$directwrite = xtrue; then + pkg_libs="${pkg_libs} -ldwrite" +fi AC_SUBST([PKG_LIBS_DEFAULT], [$(test x$enable_shared = xno && echo ${pkg_libs})]) AC_SUBST([PKG_REQUIRES_DEFAULT], [$(test x$enable_shared = xno && echo ${pkg_requires})]) diff --git a/libass/Makefile.am b/libass/Makefile.am index 4bf9584..2cf6354 100644 --- a/libass/Makefile.am +++ b/libass/Makefile.am @@ -11,7 +11,7 @@ yasm_verbose_ = $(yasm_verbose_$(AM_DEFAULT_VERBOSITY)) yasm_verbose_0 = @echo " YASM " $@; .asm.lo: - $(yasm_verbose)$(LIBTOOL) $(AM_V_lt) --mode=compile $(AS) $(ASFLAGS) -o $@ $< -prefer-non-pic + $(yasm_verbose)$(LIBTOOL) $(AM_V_lt) --tag=CC --mode=compile $(AS) $(ASFLAGS) -o $@ $< -prefer-non-pic SRC_INTEL = x86/blend_bitmaps.asm x86/blur.asm x86/cpuid.asm x86/cpuid.h SRC_INTEL64 = x86/be_blur.asm @@ -19,18 +19,29 @@ SRC_INTEL_RASTERIZER = x86/rasterizer.asm SRC_RASTERIZER = ass_rasterizer.h ass_rasterizer.c ass_rasterizer_c.c +SRC_DIRECTWRITE = ass_directwrite.c ass_directwrite.h dwrite_c.h +SRC_CORETEXT = ass_coretext.c ass_coretext.h + lib_LTLIBRARIES = libass.la -libass_la_SOURCES = ass.c ass_cache.c ass_font.c ass_fontconfig.c ass_render.c \ +libass_la_SOURCES = ass.c ass_cache.c ass_font.c ass_fontselect.c ass_render.c \ ass_utils.c ass_bitmap.c ass_blur.c ass_library.c ass_bitmap.h \ - ass_cache.h ass_fontconfig.h ass_font.h ass.h \ + ass_cache.h ass_fontselect.h ass_font.h ass.h \ 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_func_template.h + ass_shaper.h ass_strtod.c ass_fontconfig.c ass_fontconfig.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 +if DIRECTWRITE +libass_la_SOURCES += $(SRC_DIRECTWRITE) +endif + +if CORETEXT +libass_la_SOURCES += $(SRC_CORETEXT) +endif + if RASTERIZER libass_la_SOURCES += $(SRC_RASTERIZER) endif diff --git a/libass/ass.c b/libass/ass.c index 01dd2eb..b51cf2e 100644 --- a/libass/ass.c +++ b/libass/ass.c @@ -1031,7 +1031,7 @@ out: * \param bufsize out: file size * \return pointer to file contents. Caller is responsible for its deallocation. */ -static char *read_file(ASS_Library *library, char *fname, size_t *bufsize) +char *read_file(ASS_Library *library, char *fname, size_t *bufsize) { int res; long sz; diff --git a/libass/ass.h b/libass/ass.h index 774f344..5fdee10 100644 --- a/libass/ass.h +++ b/libass/ass.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> + * Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx> * * This file is part of libass. * @@ -175,6 +176,24 @@ typedef enum { int ass_library_version(void); /** + * \brief Default Font provider to load fonts in libass' database + * + * NONE don't use any default font provider for font lookup + * AUTODETECT use the first available font provider + * CORETEXT force a CoreText based font provider (OS X only) + * FONTCONFIG force a Fontconfig based font provider + * + * libass uses the best shaper available by default. + */ +typedef enum { + ASS_FONTPROVIDER_NONE = 0, + ASS_FONTPROVIDER_AUTODETECT = 1, + ASS_FONTPROVIDER_CORETEXT, + ASS_FONTPROVIDER_FONTCONFIG, + ASS_FONTPROVIDER_DIRECTWRITE, +} ASS_DefaultFontProvider; + +/** * \brief Initialize the library. * \return library handle or NULL if failed */ @@ -383,11 +402,29 @@ void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing); void ass_set_line_position(ASS_Renderer *priv, double line_position); /** + * \brief Get the list of available font providers. The output array + * is allocated with malloc and can be released with free(). If an + * allocation error occurs, size is set to (size_t)-1. + * \param priv library handle + * \param providers output, list of default providers (malloc'ed array) + * \param size output, number of providers + * \return list of available font providers (user owns the returned array) + */ +void ass_get_available_font_providers(ASS_Library *priv, + ASS_DefaultFontProvider **providers, + size_t *size); + +/** * \brief Set font lookup defaults. * \param default_font path to default font to use. Must be supplied if * fontconfig is disabled or unavailable. * \param default_family fallback font family for fontconfig, or NULL - * \param fc whether to use fontconfig + * \param dfp which font provider to use (one of ASS_DefaultFontProvider). In + * older libass version, this could be 0 or 1, where 1 enabled fontconfig. + * Newer relases also accept 0 (ASS_FONTPROVIDER_NONE) and 1 + * (ASS_FONTPROVIDER_AUTODETECT), which is almost backward-compatible. + * If the requested fontprovider does not exist or fails to initialize, the + * behavior is the same as when ASS_FONTPROVIDER_NONE was passed. * \param config path to fontconfig configuration file, or NULL. Only relevant * if fontconfig is used. * \param update whether fontconfig cache should be built/updated now. Only @@ -396,8 +433,8 @@ void ass_set_line_position(ASS_Renderer *priv, double line_position); * NOTE: font lookup must be configured before an ASS_Renderer can be used. */ void ass_set_fonts(ASS_Renderer *priv, const char *default_font, - const char *default_family, int fc, const char *config, - int update); + const char *default_family, int dfp, + const char *config, int update); /** * \brief Set selective style override mode. @@ -426,8 +463,8 @@ void ass_set_selective_style_override_enabled(ASS_Renderer *priv, int bits); void ass_set_selective_style_override(ASS_Renderer *priv, ASS_Style *style); /** - * \brief Update/build font cache. This needs to be called if it was - * disabled when ass_set_fonts was set. + * \brief This is a stub and does nothing. Old documentation: Update/build font + * cache. This needs to be called if it was disabled when ass_set_fonts was set. * * \param priv renderer handle * \return success diff --git a/libass/ass_cache.c b/libass/ass_cache.c index 2381e88..d1aaec0 100644 --- a/libass/ass_cache.c +++ b/libass/ass_cache.c @@ -43,8 +43,6 @@ static unsigned font_hash(void *buf, size_t len) hval = fnv_32a_str(desc->family, FNV1_32A_INIT); hval = fnv_32a_buf(&desc->bold, sizeof(desc->bold), hval); hval = fnv_32a_buf(&desc->italic, sizeof(desc->italic), hval); - hval = fnv_32a_buf(&desc->treat_family_as_pattern, - sizeof(desc->treat_family_as_pattern), hval); hval = fnv_32a_buf(&desc->vertical, sizeof(desc->vertical), hval); return hval; } @@ -59,8 +57,6 @@ static unsigned font_compare(void *key1, void *key2, size_t key_size) return 0; if (a->italic != b->italic) return 0; - if (a->treat_family_as_pattern != b->treat_family_as_pattern) - return 0; if (a->vertical != b->vertical) return 0; return 1; diff --git a/libass/ass_coretext.c b/libass/ass_coretext.c new file mode 100644 index 0000000..877018d --- /dev/null +++ b/libass/ass_coretext.c @@ -0,0 +1,295 @@ +/* + * 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 <CoreFoundation/CoreFoundation.h> +#include <CoreText/CoreText.h> + +#include "ass_coretext.h" + +#define SAFE_CFRelease(x) do { if (x) CFRelease(x); } while(0) + +static const ASS_FontMapping font_substitutions[] = { + {"sans-serif", "Helvetica"}, + {"serif", "Times"}, + {"monospace", "Courier"} +}; + +static char *cfstr2buf(CFStringRef string) +{ + const int encoding = kCFStringEncodingUTF8; + const char *buf_ptr = CFStringGetCStringPtr(string, encoding); + if (buf_ptr) { + return strdup(buf_ptr); + } else { + size_t len = CFStringGetLength(string); + CFIndex buf_len = CFStringGetMaximumSizeForEncoding(len, encoding); + char *buf = malloc(buf_len); + CFStringGetCString(string, buf, buf_len, encoding); + return buf; + } +} + +static void destroy_font(void *priv) +{ + CFCharacterSetRef set = priv; + SAFE_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); + SAFE_CFRelease(path); + SAFE_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); + SAFE_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); + + SAFE_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 process_descriptors(ASS_FontProvider *provider, CFArrayRef fontsd) +{ + ASS_FontProviderMetaData meta; + char *families[1]; + char *identifiers[1]; + char *fullnames[1]; + + if (!fontsd) + return; + + for (int i = 0; i < CFArrayGetCount(fontsd); i++) { + CTFontDescriptorRef fontd = CFArrayGetValueAtIndex(fontsd, i); + int index = -1; + + 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; + + int zero = 0; + get_name(fontd, kCTFontNameAttribute, identifiers, &zero); + get_name(fontd, kCTFontDisplayNameAttribute, fullnames, &meta.n_fullname); + meta.fullnames = fullnames; + + CFCharacterSetRef chset = + CTFontDescriptorCopyAttribute(fontd, kCTFontCharacterSetAttribute); + ass_font_provider_add_font(provider, &meta, path, index, + identifiers[0], (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(identifiers[0]); + + free(path); + } +} + +static void match_fonts(ASS_Library *lib, ASS_FontProvider *provider, + char *name) +{ + const size_t attributes_n = 3; + CTFontDescriptorRef ctdescrs[attributes_n]; + CFMutableDictionaryRef cfattrs[attributes_n]; + CFStringRef attributes[attributes_n] = { + kCTFontFamilyNameAttribute, + kCTFontDisplayNameAttribute, + kCTFontNameAttribute, + }; + + CFStringRef cfname = + CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8); + + for (int i = 0; i < attributes_n; i++) { + cfattrs[i] = CFDictionaryCreateMutable(NULL, 0, 0, 0); + CFDictionaryAddValue(cfattrs[i], attributes[i], cfname); + ctdescrs[i] = CTFontDescriptorCreateWithAttributes(cfattrs[i]); + } + + CFArrayRef descriptors = + CFArrayCreate(NULL, (const void **)&ctdescrs, attributes_n, NULL); + + CTFontCollectionRef ctcoll = + CTFontCollectionCreateWithFontDescriptors(descriptors, 0); + + CFArrayRef fontsd = + CTFontCollectionCreateMatchingFontDescriptors(ctcoll); + + process_descriptors(provider, fontsd); + + SAFE_CFRelease(fontsd); + SAFE_CFRelease(ctcoll); + + for (int i = 0; i < attributes_n; i++) { + SAFE_CFRelease(cfattrs[i]); + SAFE_CFRelease(ctdescrs[i]); + } + + SAFE_CFRelease(descriptors); + SAFE_CFRelease(cfname); +} + +static char *get_fallback(void *priv, const char *family, uint32_t codepoint) +{ + CFStringRef name = CFStringCreateWithBytes( + 0, (UInt8 *)family, strlen(family), kCFStringEncodingUTF8, false); + CTFontRef font = CTFontCreateWithName(name, 0, NULL); + uint32_t codepointle = OSSwapHostToLittleInt32(codepoint); + CFStringRef r = CFStringCreateWithBytes( + 0, (UInt8*)&codepointle, sizeof(codepointle), + kCFStringEncodingUTF32LE, false); + CTFontRef fb = CTFontCreateForString(font, r, CFRangeMake(0, 1)); + CFStringRef cffamily = CTFontCopyFamilyName(fb); + char *res_family = cfstr2buf(cffamily); + + SAFE_CFRelease(name); + SAFE_CFRelease(font); + SAFE_CFRelease(r); + SAFE_CFRelease(fb); + SAFE_CFRelease(cffamily); + + return res_family; +} + +static void get_substitutions(void *priv, const char *name, + ASS_FontProviderMetaData *meta) +{ + const int n = sizeof(font_substitutions) / sizeof(font_substitutions[0]); + ass_map_font(font_substitutions, n, name, meta); +} + +static ASS_FontProviderFuncs coretext_callbacks = { + .check_glyph = check_glyph, + .destroy_font = destroy_font, + .match_fonts = match_fonts, + .get_substitutions = get_substitutions, + .get_fallback = get_fallback, +}; + +ASS_FontProvider * +ass_coretext_add_provider(ASS_Library *lib, ASS_FontSelector *selector, + const char *config) +{ + return ass_font_provider_new(selector, &coretext_callbacks, NULL); +} diff --git a/libass/ass_coretext.h b/libass/ass_coretext.h new file mode 100644 index 0000000..07a49fa --- /dev/null +++ b/libass/ass_coretext.h @@ -0,0 +1,35 @@ +/* + * 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, + const char *config); + +#endif + +#endif diff --git a/libass/ass_directwrite.c b/libass/ass_directwrite.c new file mode 100644 index 0000000..f11deb6 --- /dev/null +++ b/libass/ass_directwrite.c @@ -0,0 +1,715 @@ +/* + * Copyright (C) 2015 Stephan Vedder <stephan.vedder@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. + */ +#define COBJMACROS + +#include "config.h" + +#include <initguid.h> +#include <ole2.h> +#include <shobjidl.h> + +#include "dwrite_c.h" + +#include "ass_directwrite.h" +#include "ass_utils.h" + +#define NAME_MAX_LENGTH 256 +#define FALLBACK_DEFAULT_FONT L"Arial" + +static const ASS_FontMapping font_substitutions[] = { + {"sans-serif", "Arial"}, + {"serif", "Times New Roman"}, + {"monospace", "Courier New"} +}; + +/* + * The private data stored for every font, detected by this backend. + */ +typedef struct { + IDWriteFont *font; + IDWriteFontFileStream *stream; +} FontPrivate; + +typedef struct { + HMODULE directwrite_lib; + IDWriteFactory *factory; +} ProviderPrivate; + +/** + * Custom text renderer class for logging the fonts used. It does not + * actually render anything or do anything apart from that. + */ + +typedef struct FallbackLogTextRenderer { + IDWriteTextRenderer iface; + IDWriteTextRendererVtbl vtbl; + IDWriteFactory *dw_factory; + LONG ref_count; +} FallbackLogTextRenderer; + +static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_IsPixelSnappingDisabled( + IDWriteTextRenderer *This, + _In_opt_ void* clientDrawingContext, + _Out_ BOOL* isDisabled + ) +{ + *isDisabled = true; + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_GetCurrentTransform( + IDWriteTextRenderer *This, + _In_opt_ void* clientDrawingContext, + _Out_ DWRITE_MATRIX* transform + ) +{ + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_GetPixelsPerDip( + IDWriteTextRenderer *This, + _In_opt_ void* clientDrawingContext, + _Out_ FLOAT* pixelsPerDip + ) +{ + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_DrawGlyphRun( + IDWriteTextRenderer *This, + _In_opt_ void* clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + DWRITE_MEASURING_MODE measuringMode, + _In_ DWRITE_GLYPH_RUN const* glyphRun, + _In_ DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, + IUnknown* clientDrawingEffect + ) +{ + FallbackLogTextRenderer *this = (FallbackLogTextRenderer *)This; + HRESULT hr; + IDWriteFontCollection *font_coll = NULL; + IDWriteFont **font = (IDWriteFont **)clientDrawingContext; + + hr = IDWriteFactory_GetSystemFontCollection(this->dw_factory, &font_coll, FALSE); + if (FAILED(hr)) + return E_FAIL; + + hr = IDWriteFontCollection_GetFontFromFontFace(font_coll, glyphRun->fontFace, + font); + if (FAILED(hr)) + return E_FAIL; + + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_DrawUnderline( + IDWriteTextRenderer *This, + _In_opt_ void* clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + _In_ DWRITE_UNDERLINE const* underline, + IUnknown* clientDrawingEffect + ) +{ + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_DrawStrikethrough( + IDWriteTextRenderer *This, + _In_opt_ void* clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + _In_ DWRITE_STRIKETHROUGH const* strikethrough, + IUnknown* clientDrawingEffect + ) +{ + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_DrawInlineObject( + IDWriteTextRenderer *This, + void *clientDrawingContext, + FLOAT originX, + FLOAT originY, + IDWriteInlineObject *inlineObject, + WINBOOL isSideways, + WINBOOL isRightToLeft, + IUnknown *clientDrawingEffect + ) +{ + return S_OK; +} + +// IUnknown methods + +static ULONG STDMETHODCALLTYPE FallbackLogTextRenderer_AddRef( + IDWriteTextRenderer *This + ) +{ + FallbackLogTextRenderer *this = (FallbackLogTextRenderer *)This; + return InterlockedIncrement(&this->ref_count); +} + +static ULONG STDMETHODCALLTYPE FallbackLogTextRenderer_Release( + IDWriteTextRenderer *This + ) +{ + FallbackLogTextRenderer *this = (FallbackLogTextRenderer *)This; + unsigned long new_count = InterlockedDecrement(&this->ref_count); + if (new_count == 0) { + free(this); + return 0; + } + + return new_count; +} + +static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_QueryInterface( + IDWriteTextRenderer *This, + REFIID riid, + void **ppvObject + ) +{ + if (IsEqualGUID(riid, &IID_IDWriteTextRenderer) + || IsEqualGUID(riid, &IID_IDWritePixelSnapping) + || IsEqualGUID(riid, &IID_IUnknown)) { + *ppvObject = This; + } else { + *ppvObject = NULL; + return E_FAIL; + } + + This->lpVtbl->AddRef(This); + return S_OK; +} + +static void init_FallbackLogTextRenderer(FallbackLogTextRenderer *r, + IDWriteFactory *factory) +{ + *r = (FallbackLogTextRenderer){ + .iface = { + .lpVtbl = &r->vtbl, + }, + .vtbl = { + FallbackLogTextRenderer_QueryInterface, + FallbackLogTextRenderer_AddRef, + FallbackLogTextRenderer_Release, + FallbackLogTextRenderer_IsPixelSnappingDisabled, + FallbackLogTextRenderer_GetCurrentTransform, + FallbackLogTextRenderer_GetPixelsPerDip, + FallbackLogTextRenderer_DrawGlyphRun, + FallbackLogTextRenderer_DrawUnderline, + FallbackLogTextRenderer_DrawStrikethrough, + FallbackLogTextRenderer_DrawInlineObject, + }, + .dw_factory = factory, + }; +} + +/* + * This function is called whenever a font is used for the first + * time. It will create a FontStream for memory reading, which + * will be stored within the private data. + */ +static bool init_font_private(FontPrivate *priv) +{ + HRESULT hr = S_OK; + IDWriteFont *font = priv->font; + IDWriteFontFace *face = NULL; + IDWriteFontFile *file = NULL; + IDWriteFontFileStream *stream = NULL; + IDWriteFontFileLoader *loader = NULL; + UINT32 n_files = 1; + const void *refKey = NULL; + UINT32 keySize = 0; + + if (priv->stream != NU |