123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- //
- // UIFont+YYAdd.m
- // YYKit <https://github.com/ibireme/YYKit>
- //
- // Created by ibireme on 14/5/11.
- // Copyright (c) 2015 ibireme.
- //
- // This source code is licensed under the MIT-style license found in the
- // LICENSE file in the root directory of this source tree.
- //
- #import "UIFont+YYAdd.h"
- #import "YYKitMacro.h"
- YYSYNTH_DUMMY_CLASS(UIFont_YYAdd)
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wprotocol"
- // Apple has implemented UIFont<NSCoding>, but did not make it public.
- @implementation UIFont (YYAdd)
- - (BOOL)isBold {
- if (![self respondsToSelector:@selector(fontDescriptor)]) return NO;
- return (self.fontDescriptor.symbolicTraits & UIFontDescriptorTraitBold) > 0;
- }
- - (BOOL)isItalic {
- if (![self respondsToSelector:@selector(fontDescriptor)]) return NO;
- return (self.fontDescriptor.symbolicTraits & UIFontDescriptorTraitItalic) > 0;
- }
- - (BOOL)isMonoSpace {
- if (![self respondsToSelector:@selector(fontDescriptor)]) return NO;
- return (self.fontDescriptor.symbolicTraits & UIFontDescriptorTraitMonoSpace) > 0;
- }
- - (BOOL)isColorGlyphs {
- if (![self respondsToSelector:@selector(fontDescriptor)]) return NO;
- return (CTFontGetSymbolicTraits((__bridge CTFontRef)self) & kCTFontTraitColorGlyphs) != 0;
- }
- - (CGFloat)fontWeight {
- NSDictionary *traits = [self.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute];
- return [traits[UIFontWeightTrait] floatValue];
- }
- - (UIFont *)fontWithBold {
- if (![self respondsToSelector:@selector(fontDescriptor)]) return self;
- return [UIFont fontWithDescriptor:[self.fontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold] size:self.pointSize];
- }
- - (UIFont *)fontWithItalic {
- if (![self respondsToSelector:@selector(fontDescriptor)]) return self;
- return [UIFont fontWithDescriptor:[self.fontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitItalic] size:self.pointSize];
- }
- - (UIFont *)fontWithBoldItalic {
- if (![self respondsToSelector:@selector(fontDescriptor)]) return self;
- return [UIFont fontWithDescriptor:[self.fontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold | UIFontDescriptorTraitItalic] size:self.pointSize];
- }
- - (UIFont *)fontWithNormal {
- if (![self respondsToSelector:@selector(fontDescriptor)]) return self;
- return [UIFont fontWithDescriptor:[self.fontDescriptor fontDescriptorWithSymbolicTraits:0] size:self.pointSize];
- }
- + (UIFont *)fontWithCTFont:(CTFontRef)CTFont {
- if (!CTFont) return nil;
- CFStringRef name = CTFontCopyPostScriptName(CTFont);
- if (!name) return nil;
- CGFloat size = CTFontGetSize(CTFont);
- UIFont *font = [self fontWithName:(__bridge NSString *)(name) size:size];
- CFRelease(name);
- return font;
- }
- + (UIFont *)fontWithCGFont:(CGFontRef)CGFont size:(CGFloat)size {
- if (!CGFont) return nil;
- CFStringRef name = CGFontCopyPostScriptName(CGFont);
- if (!name) return nil;
- UIFont *font = [self fontWithName:(__bridge NSString *)(name) size:size];
- CFRelease(name);
- return font;
- }
- - (CTFontRef)CTFontRef CF_RETURNS_RETAINED {
- CTFontRef font = CTFontCreateWithName((__bridge CFStringRef)self.fontName, self.pointSize, NULL);
- return font;
- }
- - (CGFontRef)CGFontRef CF_RETURNS_RETAINED {
- CGFontRef font = CGFontCreateWithFontName((__bridge CFStringRef)self.fontName);
- return font;
- }
- + (BOOL)loadFontFromPath:(NSString *)path {
- NSURL *url = [NSURL fileURLWithPath:path];
- CFErrorRef error;
- BOOL suc = CTFontManagerRegisterFontsForURL((__bridge CFTypeRef)url, kCTFontManagerScopeNone, &error);
- if (!suc) {
- NSLog(@"Failed to load font: %@", error);
- }
- return suc;
- }
- + (void)unloadFontFromPath:(NSString *)path {
- NSURL *url = [NSURL fileURLWithPath:path];
- CTFontManagerUnregisterFontsForURL((__bridge CFTypeRef)url, kCTFontManagerScopeNone, NULL);
- }
- + (UIFont *)loadFontFromData:(NSData *)data {
- CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
- if (!provider) return nil;
- CGFontRef fontRef = CGFontCreateWithDataProvider(provider);
- CGDataProviderRelease(provider);
- if (!fontRef) return nil;
-
- CFErrorRef errorRef;
- BOOL suc = CTFontManagerRegisterGraphicsFont(fontRef, &errorRef);
- if (!suc) {
- CFRelease(fontRef);
- NSLog(@"%@", errorRef);
- return nil;
- } else {
- CFStringRef fontName = CGFontCopyPostScriptName(fontRef);
- UIFont *font = [UIFont fontWithName:(__bridge NSString *)(fontName) size:[UIFont systemFontSize]];
- if (fontName) CFRelease(fontName);
- CGFontRelease(fontRef);
- return font;
- }
- }
- + (BOOL)unloadFontFromData:(UIFont *)font {
- CGFontRef fontRef = CGFontCreateWithFontName((__bridge CFStringRef)font.fontName);
- if (!fontRef) return NO;
- CFErrorRef errorRef;
- BOOL suc = CTFontManagerUnregisterGraphicsFont(fontRef, &errorRef);
- CFRelease(fontRef);
- if (!suc) NSLog(@"%@", errorRef);
- return suc;
- }
- + (NSData *)dataFromFont:(UIFont *)font {
- CGFontRef cgFont = font.CGFontRef;
- NSData *data = [self dataFromCGFont:cgFont];
- CGFontRelease(cgFont);
- return data;
- }
- typedef struct FontHeader {
- int32_t fVersion;
- uint16_t fNumTables;
- uint16_t fSearchRange;
- uint16_t fEntrySelector;
- uint16_t fRangeShift;
- } FontHeader;
- typedef struct TableEntry {
- uint32_t fTag;
- uint32_t fCheckSum;
- uint32_t fOffset;
- uint32_t fLength;
- } TableEntry;
- static uint32_t CalcTableCheckSum(const uint32_t *table, uint32_t numberOfBytesInTable) {
- uint32_t sum = 0;
- uint32_t nLongs = (numberOfBytesInTable + 3) / 4;
- while (nLongs-- > 0) {
- sum += CFSwapInt32HostToBig(*table++);
- }
- return sum;
- }
- //Reference:
- //https://github.com/google/skia/blob/master/src%2Fports%2FSkFontHost_mac.cpp
- + (NSData *)dataFromCGFont:(CGFontRef)cgFont {
- if (!cgFont) return nil;
-
- CFRetain(cgFont);
-
- CFArrayRef tags = CGFontCopyTableTags(cgFont);
- if (!tags) return nil;
- CFIndex tableCount = CFArrayGetCount(tags);
-
- size_t *tableSizes = malloc(sizeof(size_t) * tableCount);
- memset(tableSizes, 0, sizeof(size_t) * tableCount);
-
- BOOL containsCFFTable = NO;
-
- size_t totalSize = sizeof(FontHeader) + sizeof(TableEntry) * tableCount;
-
- for (CFIndex index = 0; index < tableCount; index++) {
- size_t tableSize = 0;
- uint32_t aTag = (uint32_t)CFArrayGetValueAtIndex(tags, index);
- if (aTag == kCTFontTableCFF && !containsCFFTable) {
- containsCFFTable = YES;
- }
- CFDataRef tableDataRef = CGFontCopyTableForTag(cgFont, aTag);
- if (tableDataRef) {
- tableSize = CFDataGetLength(tableDataRef);
- CFRelease(tableDataRef);
- }
- totalSize += (tableSize + 3) & ~3;
- tableSizes[index] = tableSize;
- }
-
- unsigned char *stream = malloc(totalSize);
- memset(stream, 0, totalSize);
- char *dataStart = (char *)stream;
- char *dataPtr = dataStart;
-
- // compute font header entries
- uint16_t entrySelector = 0;
- uint16_t searchRange = 1;
- while (searchRange < tableCount >> 1) {
- entrySelector++;
- searchRange <<= 1;
- }
- searchRange <<= 4;
-
- uint16_t rangeShift = (tableCount << 4) - searchRange;
-
- // write font header (also called sfnt header, offset subtable)
- FontHeader *offsetTable = (FontHeader *)dataPtr;
-
- //OpenType Font contains CFF Table use 'OTTO' as version, and with .otf extension
- //otherwise 0001 0000
- offsetTable->fVersion = containsCFFTable ? 'OTTO' : CFSwapInt16HostToBig(1);
- offsetTable->fNumTables = CFSwapInt16HostToBig((uint16_t)tableCount);
- offsetTable->fSearchRange = CFSwapInt16HostToBig((uint16_t)searchRange);
- offsetTable->fEntrySelector = CFSwapInt16HostToBig((uint16_t)entrySelector);
- offsetTable->fRangeShift = CFSwapInt16HostToBig((uint16_t)rangeShift);
-
- dataPtr += sizeof(FontHeader);
-
- // write tables
- TableEntry *entry = (TableEntry *)dataPtr;
- dataPtr += sizeof(TableEntry) * tableCount;
-
- for (int index = 0; index < tableCount; ++index) {
- uint32_t aTag = (uint32_t)CFArrayGetValueAtIndex(tags, index);
- CFDataRef tableDataRef = CGFontCopyTableForTag(cgFont, aTag);
- size_t tableSize = CFDataGetLength(tableDataRef);
-
- memcpy(dataPtr, CFDataGetBytePtr(tableDataRef), tableSize);
-
- entry->fTag = CFSwapInt32HostToBig((uint32_t)aTag);
- entry->fCheckSum = CFSwapInt32HostToBig(CalcTableCheckSum((uint32_t *)dataPtr, (uint32_t)tableSize));
-
- uint32_t offset = (uint32_t)dataPtr - (uint32_t)dataStart;
- entry->fOffset = CFSwapInt32HostToBig((uint32_t)offset);
- entry->fLength = CFSwapInt32HostToBig((uint32_t)tableSize);
- dataPtr += (tableSize + 3) & ~3;
- ++entry;
- CFRelease(tableDataRef);
- }
-
- CFRelease(cgFont);
- CFRelease(tags);
- free(tableSizes);
- NSData *fontData = [NSData dataWithBytesNoCopy:stream length:totalSize freeWhenDone:YES];
- return fontData;
- }
- @end
- #pragma clang diagnostic pop
|