summary refs log tree commit diff stats
path: root/libs/FontLabel/ZFont.m
diff options
context:
space:
mode:
Diffstat (limited to 'libs/FontLabel/ZFont.m')
-rwxr-xr-xlibs/FontLabel/ZFont.m170
1 files changed, 170 insertions, 0 deletions
diff --git a/libs/FontLabel/ZFont.m b/libs/FontLabel/ZFont.m new file mode 100755 index 0000000..793b13a --- /dev/null +++ b/libs/FontLabel/ZFont.m
@@ -0,0 +1,170 @@
1//
2// ZFont.m
3// FontLabel
4//
5// Created by Kevin Ballard on 7/2/09.
6// Copyright © 2009 Zynga Game Networks
7//
8//
9// Licensed under the Apache License, Version 2.0 (the "License");
10// you may not use this file except in compliance with the License.
11// You may obtain a copy of the License at
12//
13// http://www.apache.org/licenses/LICENSE-2.0
14//
15// Unless required by applicable law or agreed to in writing, software
16// distributed under the License is distributed on an "AS IS" BASIS,
17// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18// See the License for the specific language governing permissions and
19// limitations under the License.
20//
21
22#import "ZFont.h"
23
24@interface ZFont ()
25@property (nonatomic, readonly) CGFloat ratio;
26- (NSString *)copyNameTableEntryForID:(UInt16)nameID;
27@end
28
29@implementation ZFont
30@synthesize cgFont=_cgFont, pointSize=_pointSize, ratio=_ratio;
31
32+ (ZFont *)fontWithCGFont:(CGFontRef)cgFont size:(CGFloat)fontSize {
33 return [[[self alloc] initWithCGFont:cgFont size:fontSize] autorelease];
34}
35
36+ (ZFont *)fontWithUIFont:(UIFont *)uiFont {
37 NSParameterAssert(uiFont != nil);
38 CGFontRef cgFont = CGFontCreateWithFontName((CFStringRef)uiFont.fontName);
39 ZFont *zFont = [[self alloc] initWithCGFont:cgFont size:uiFont.pointSize];
40 CGFontRelease(cgFont);
41 return [zFont autorelease];
42}
43
44- (id)initWithCGFont:(CGFontRef)cgFont size:(CGFloat)fontSize {
45 if ((self = [super init])) {
46 _cgFont = CGFontRetain(cgFont);
47 _pointSize = fontSize;
48 _ratio = fontSize/CGFontGetUnitsPerEm(cgFont);
49 }
50 return self;
51}
52
53- (id)init {
54 NSAssert(NO, @"-init is not valid for ZFont");
55 return nil;
56}
57
58- (CGFloat)ascender {
59 return ceilf(self.ratio * CGFontGetAscent(self.cgFont));
60}
61
62- (CGFloat)descender {
63 return floorf(self.ratio * CGFontGetDescent(self.cgFont));
64}
65
66- (CGFloat)leading {
67 return (self.ascender - self.descender);
68}
69
70- (CGFloat)capHeight {
71 return ceilf(self.ratio * CGFontGetCapHeight(self.cgFont));
72}
73
74- (CGFloat)xHeight {
75 return ceilf(self.ratio * CGFontGetXHeight(self.cgFont));
76}
77
78- (NSString *)familyName {
79 if (_familyName == nil) {
80 _familyName = [self copyNameTableEntryForID:1];
81 }
82 return _familyName;
83}
84
85- (NSString *)fontName {
86 if (_fontName == nil) {
87 _fontName = [self copyNameTableEntryForID:4];
88 }
89 return _fontName;
90}
91
92- (NSString *)postScriptName {
93 if (_postScriptName == nil) {
94 _postScriptName = [self copyNameTableEntryForID:6];
95 }
96 return _postScriptName;
97}
98
99- (ZFont *)fontWithSize:(CGFloat)fontSize {
100 if (fontSize == self.pointSize) return self;
101 NSParameterAssert(fontSize > 0.0);
102 return [[[ZFont alloc] initWithCGFont:self.cgFont size:fontSize] autorelease];
103}
104
105- (BOOL)isEqual:(id)object {
106 if (![object isKindOfClass:[ZFont class]]) return NO;
107 ZFont *font = (ZFont *)object;
108 return (font.cgFont == self.cgFont && font.pointSize == self.pointSize);
109}
110
111- (NSString *)copyNameTableEntryForID:(UInt16)aNameID {
112 CFDataRef nameTable = CGFontCopyTableForTag(self.cgFont, 'name');
113 NSAssert1(nameTable != NULL, @"CGFontCopyTableForTag returned NULL for 'name' tag in font %@",
114 [(id)CFCopyDescription(self.cgFont) autorelease]);
115 const UInt8 * const bytes = CFDataGetBytePtr(nameTable);
116 NSAssert1(OSReadBigInt16(bytes, 0) == 0, @"name table for font %@ has bad version number",
117 [(id)CFCopyDescription(self.cgFont) autorelease]);
118 const UInt16 count = OSReadBigInt16(bytes, 2);
119 const UInt16 stringOffset = OSReadBigInt16(bytes, 4);
120 const UInt8 * const nameRecords = &bytes[6];
121 UInt16 nameLength = 0;
122 UInt16 nameOffset = 0;
123 NSStringEncoding encoding = 0;
124 for (UInt16 idx = 0; idx < count; idx++) {
125 const uintptr_t recordOffset = 12 * idx;
126 const UInt16 nameID = OSReadBigInt16(nameRecords, recordOffset + 6);
127 if (nameID != aNameID) continue;
128 const UInt16 platformID = OSReadBigInt16(nameRecords, recordOffset + 0);
129 const UInt16 platformSpecificID = OSReadBigInt16(nameRecords, recordOffset + 2);
130 encoding = 0;
131 // for now, we only support a subset of encodings
132 switch (platformID) {
133 case 0: // Unicode
134 encoding = NSUTF16StringEncoding;
135 break;
136 case 1: // Macintosh
137 switch (platformSpecificID) {
138 case 0:
139 encoding = NSMacOSRomanStringEncoding;
140 break;
141 }
142 case 3: // Microsoft
143 switch (platformSpecificID) {
144 case 1:
145 encoding = NSUTF16StringEncoding;
146 break;
147 }
148 }
149 if (encoding == 0) continue;
150 nameLength = OSReadBigInt16(nameRecords, recordOffset + 8);
151 nameOffset = OSReadBigInt16(nameRecords, recordOffset + 10);
152 break;
153 }
154 NSString *result = nil;
155 if (nameOffset > 0) {
156 const UInt8 *nameBytes = &bytes[stringOffset + nameOffset];
157 result = [[NSString alloc] initWithBytes:nameBytes length:nameLength encoding:encoding];
158 }
159 CFRelease(nameTable);
160 return result;
161}
162
163- (void)dealloc {
164 CGFontRelease(_cgFont);
165 [_familyName release];
166 [_fontName release];
167 [_postScriptName release];
168 [super dealloc];
169}
170@end