From 4e7fb5e264aa84f16de198474c0504c844ee7f1b Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Fri, 3 Nov 2017 15:51:21 -0400 Subject: [PATCH] Added code that handles all the attribute stuff for a CTFontRef AND CTFontDescriptorRef for us; we'll use this throughout the various font style files instead of doing everything ourselves. --- doc/export/fontmatch.m | 257 +++++++++++++++++++++++++++++++++++++++++ doc/export/fontstyle.h | 56 +++++++++ 2 files changed, 313 insertions(+) create mode 100644 doc/export/fontstyle.h diff --git a/doc/export/fontmatch.m b/doc/export/fontmatch.m index fe2dceae..74cbe2e1 100644 --- a/doc/export/fontmatch.m +++ b/doc/export/fontmatch.m @@ -25,6 +25,263 @@ // because the descriptors returned by Core Text's own font // matching won't have any. +@implementation fontStyleData + +- (id)initWithFont:(CTFontRef)f +{ + self = [super init]; + if (self) { + self->font = f; + CFRetain(self->font); + self->desc = CTFontCopyDescriptor(self->font); + if (![self prepare]) { + [self release]; + return nil; + } + } + return self; +} + +- (id)initWithDescriptor:(CTFontDescriptorRef)d +{ + self = [super init]; + if (self) { + self->font = NULL; + self->desc = d; + CFRetain(self->desc); + if (![self prepare]) { + [self release]; + return nil; + } + } + return self; +} + +- (void)dealloc +{ +#define REL(x) if (x != NULL) { CFRelease(x); x = NULL; } + REL(self->variationAxes); + REL(self->familyName); + REL(self->preferredFamilyName); + REL(self->fullName); + REL(self->subFamilyName); + REL(self->preferredSubFamilyName); + REL(self->postScriptName); + REL(self->variations); + REL(self->styleName); + REL(self->traits); + CFRelease(self->desc); + REL(self->font); + [super dealloc]; +} + +- (BOOL)prepare +{ + CFNumberRef num; + + self->traits = NULL; + self->symbolic = 0; + self->weight = 0; + self->width = 0; + self->didStyleName = NO; + self->styleName = NULL; + self->didVariations = NO; + self->variations = NULL; + self->didRegistrationScope = NO; + self->hasRegistrationScope = NO; + self->registrationScope = 0; + self->didPostScriptName = NO; + self->postScriptName = NULL; + self->didFontFormat = NO; + self->fontFormat = 0; + self->didPreferredSubFamilyName = NO; + self->preferredSubFamilyName = NULL; + self->didSubFamilyName = NO; + self->subFamilyName = NULL; + self->didFullName = NO; + self->fullName = NULL; + self->didPreferredFamilyName = NO; + self->preferredFamilyName = NULL; + self->didFamilyName = NO; + self->familyName = NULL; + self->didVariationAxes = NO; + self->variationAxes = NULL; + + self->traits = (CFDictionaryRef) CTFontDescriptorCopyAttribute(self->desc, kCTFontTraitsAttribute); + if (self->traits == NULL) + return NO; + + num = (CFNumberRef) CFDictionaryGetValue(self->traits, kCTFontSymbolicTrait); + if (num == NULL) + return NO; + if (CFNumberGetValue(num, kCFNumberSInt32Type, &(self->symbolic)) == false) + return NO; + + num = (CFNumberRef) CFDictionaryGetValue(self->traits, kCTFontWeightTrait); + if (num == NULL) + return NO; + if (CFNumberGetValue(num, kCFNumberDoubleType, &(self->weight)) == false) + return NO; + + num = (CFNumberRef) CFDictionaryGetValue(self->traits, kCTFontWidthTrait); + if (num == NULL) + return NO; + if (CFNumberGetValue(num, kCFNumberDoubleType, &(self->width)) == false) + return NO; + + return YES; +} + +- (void)ensureFont +{ + if (self->font != NULL) + return; + self->font = CTFontCreateWithFontDescriptor(self->desc, 0.0, NULL); +} + +- (CTFontSymbolicTraits)symbolicTraits +{ + return self->symbolic; +} + +- (double)weight +{ + return self->weight; +} + +- (double)width +{ + return self->width; +} + +- (CFStringRef)styleName +{ + if (!self->didStyleName) { + self->didStyleName = YES; + self->styleName = (CFStringRef) CTFontDescriptorCopyAttribute(self->desc, kCTFontStyleNameAttribute); + // The code we use this for (guessItalicOblique() below) checks if this is NULL or not, so we're good. + } + return self->styleName; +} + +- (CFDictionaryRef)variations +{ + if (!self->didVariations) { + self->didVariations = YES; + self->variations = (CFDictionaryRef) CTFontDescriptorCopyAttribute(self->desc, kCTFontVariationsAttribute); + // This being NULL is used to determine whether a font uses variations at all, so we don't need to worry now. + } + return self->variations; +} + +- (BOOL)hasRegistrationScope +{ + if (!self->didRegistrationScope) { + CFNumberRef num; + + self->didRegistrationScope = YES; + num = (CFNumberRef) CTFontDescriptorCopyAttribute(desc, kCTFontRegistrationScopeAttribute); + self->hasRegistrationScope = num != NULL; + if (self->hasRegistrationScope) { + if (CFNumberGetValue(num, kCFNumberSInt32Type, &(self->registrationScope)) == false) { + // TODO + } + CFRelease(num); + } + } + return self->hasRegistrationScope; +} + +- (CTFontManagerScope)registrationScope +{ + [self hasRegistrationScope]; + return self->registrationScope; +} + +- (CFStringRef)postScriptName +{ + if (!self->didPostScriptName) { + self->didPostScriptName = YES; + [self ensureFont]; + self->postScriptName = CTFontCopyPostScriptName(self->font); + } + return self->postScriptName; +} + +- (CFDataRef)table:(CTFontTableTag)tag +{ + [self ensureFont]; + return CTFontCopyTable(self->font, tag, kCTFontTableOptionNoOptions); +} + +- (CTFontFormat)fontFormat +{ + if (!self->didFontFormat) { + CFNumberRef num; + + self->didFontFormat = YES; + num = (CFNumberRef) CTFontDescriptorCopyAttribute(self->desc, kCTFontFormatAttribute); + if (num == NULL) { + // TODO + } + if (CFNumberGetValue(num, kCFNumberSInt32Type, &(self->fontFormat)) == false) { + // TODO + } + CFRelease(num); + } + return self->fontFormat; +} + +// We don't need to worry if this or any of the functions that use it return NULL, because the code that uses it (libFontRegistry.dylib bug workarounds in fonttraits.m) checks for NULL. +- (CFStringRef)fontName:(CFStringRef)key +{ + [self ensureFont]; + return CTFontCopyName(self->font, key); +} + +#define FONTNAME(sel, did, var, key) \ + - (CFString)sel \ + { \ + if (!did) { \ + did = YES; \ + var = [self fontName:key]; \ + } \ + return var; \ + } +FONTNAME(preferredSubFamilyName, + self->didPreferredSubFamilyName, + self->preferredSubFamilyName, + kCTFontPreferredSubFamilyNameKey) +FONTNAME(subFamilyName, + self->didSubFamilyName, + self->subFamilyName, + kCTFontSubFamilyNameKey) +FONTNAME(fullName, + self->didFullName, + self->fullName, + kCTFontFullNameKey) +FONTNAME(preferredFamilyName, + self->didPreferredFamilyName, + self->preferredFamilyName, + kCTFontPreferredFamilyNameKey) +FONTNAME(familyName, + self->didFamilyName, + self->familyName, + kCTFontFamilyNameKey) + +- (CFArrayRef)variationAxes +{ + if (!self->didVariationAxes) { + self->didVariationAxes = YES; + [self ensureFont]; + self->variationAxes = CTFontCopyVariationAxes(self->font); + // We don't care about the return value because we call this only on fonts that we know have variations anyway. + } + return self->variationAxes; +} + +@end + struct closeness { CFIndex index; double weight; diff --git a/doc/export/fontstyle.h b/doc/export/fontstyle.h new file mode 100644 index 00000000..c94ef3fd --- /dev/null +++ b/doc/export/fontstyle.h @@ -0,0 +1,56 @@ +// 3 november 2017 + +// fontstyle.m +@interface fontStyleData : NSObject { + CTFontRef font; + CTFontDescriptorRef desc; + CFDictionaryRef traits; + CTFontSymbolicTraits symbolic; + double weight; + double width; + BOOL didStyleName; + CFStringRef styleName; + BOOL didVariations; + CFDictionaryRef variations; + BOOL didRegistrationScope; + BOOL hasRegistrationScope; + CTFontManagerScope registrationScope; + BOOL didPostScriptName; + CFStringRef postScriptName; + BOOL didFontFormat; + CTFontFormat fontFormat; + BOOL didPreferredSubFamilyName; + CFStringRef preferredSubFamilyName; + BOOL didSubFamilyName; + CFStringRef subFamilyName; + BOOL didFullName; + CFStringRef fullName; + BOOL didPreferredFamilyName; + CFStringRef preferredFamilyName; + BOOL didFamilyName; + CFStringRef familyName; + BOOL didVariationAxes; + CFArrayRef variationAxes; +} +- (id)initWithFont:(CTFontRef)f; +- (id)initWithDescriptor:(CTFontDescriptorRef)d; +- (BOOL)prepare; +- (void)ensureFont; +- (CTFontSymbolicTraits)symbolicTraits; +- (double)weight; +- (double)width; +- (CFStringRef)styleName; +- (CFDictionaryRef)variations; +- (BOOL)hasRegistrationScope; +- (CTFontManagerScope)registrationScope; +- (CFStringRef)postScriptName; +- (CFDataRef)table:(CTFontTableTag)tag; +- (CTFontFormat)fontFormat; +- (CFStringRef)fontName:(CFStringRef)key; +- (CFStringRef)preferredSubFamilyName; +- (CFStringRef)subFamilyName; +- (CFStringRef)fullName; +- (CFStringRef)preferredFamilyName; +- (CFStringRef)familyName; +- (CFArrayRef)variationAxes; +@end