diff options
author | Grigori Goronzy <greg@chown.ath.cx> | 2015-09-07 11:40:54 +0200 |
---|---|---|
committer | Grigori Goronzy <greg@chown.ath.cx> | 2015-09-07 11:40:54 +0200 |
commit | a2f12d6f79bfdc6bc7c1cb6ddd3a42c97ab2de4f (patch) | |
tree | 2600406db3d71a17d4389f34ba4bf66f7c098247 /libass/ass_coretext.c | |
parent | 23de9995103c16ceceba19cae87e328be12fa8e4 (diff) | |
parent | 0268c64b8ec7bef9287a212759152bf7d15e64d8 (diff) | |
download | libass-a2f12d6f79bfdc6bc7c1cb6ddd3a42c97ab2de4f.tar.bz2 libass-a2f12d6f79bfdc6bc7c1cb6ddd3a42c97ab2de4f.tar.xz |
Merge branch 'fonts'
Diffstat (limited to 'libass/ass_coretext.c')
-rw-r--r-- | libass/ass_coretext.c | 295 |
1 files changed, 295 insertions, 0 deletions
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); +} |