5 #define Cursor OSXCursor
6 #include <Carbon/Carbon.h>
18 extern void CGFontGetGlyphsForUnichars(CGFontRef, const UniChar[], const CGGlyph[], size_t);
20 // In these fonts, it's too hard to distinguish U+2018 and U+2019,
21 // so don't map the ASCII quotes there.
22 // See https://github.com/9fans/plan9port/issues/86
23 static char *skipquotemap[] = {
29 mapUnicode(char *name, int i)
33 if(0xd800 <= i && i < 0xe000) // surrogate pairs, will crash OS X libraries!
35 for(j=0; j<nelem(skipquotemap); j++) {
36 if(strstr(name, skipquotemap[j]))
54 n = CFStringGetLength(s)*8;
56 CFStringGetCString(s, p, n, kCFStringEncodingUTF8);
63 return CFStringCreateWithBytes(nil, (uchar*)p, strlen(p), kCFStringEncodingUTF8, false);
67 mac2r(CGRect r, int size, int unit)
71 rr.min.x = r.origin.x*size/unit;
72 rr.min.y = r.origin.y*size/unit;
73 rr.max.x = (r.origin.x+r.size.width)*size/unit + 0.99999999;
74 rr.max.y = (r.origin.x+r.size.width)*size/unit + 0.99999999;
79 meminvert(Memimage *m)
83 p = byteaddr(m, m->r.min);
84 ep = p + 4*m->width*Dy(m->r);
93 CTFontCollectionRef allc;
96 CTFontDescriptorRef f;
98 allc = CTFontCollectionCreateFromAvailableFonts(0);
99 array = CTFontCollectionCreateMatchingFontDescriptors(allc);
100 n = CFArrayGetCount(array);
101 xfont = emalloc9p(n*sizeof xfont[0]);
103 f = (void*)CFArrayGetValueAtIndex(array, i);
106 s = CTFontDescriptorCopyAttribute(f, kCTFontNameAttribute);
107 xfont[nxfont].name = mac2c(s);
113 // Some representative text to try to discern line heights.
114 static char *lines[] = {
115 "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
116 "abcdefghijklmnopqrstuvwxyz",
119 "ὕαλον ϕαγεῖν δύναμαι· τοῦτο οὔ με βλάπτει.",
120 "私はガラスを食べられます。それは私を傷つけません。",
121 "Aš galiu valgyti stiklą ir jis manęs nežeidžia",
122 "Môžem jesť sklo. Nezraní ma.",
126 fontheight(XFont *f, int size, int *height, int *ascent)
132 CTFontDescriptorRef desc;
134 CGColorSpaceRef color;
137 desc = CTFontDescriptorCreateWithNameAndSize(s, size);
141 font = CTFontCreateWithFontDescriptor(desc, 0, nil);
146 color = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
147 ctxt = CGBitmapContextCreate(nil, 1, 1, 8, 1, color, kCGImageAlphaNone);
148 CGColorSpaceRelease(color);
149 CGContextSetTextPosition(ctxt, 0, 0);
151 for(i=0; i<nelem(lines); i++) {
152 CFStringRef keys[] = { kCTFontAttributeName };
153 CFTypeRef values[] = { font };
155 CFDictionaryRef attrs;
156 CFAttributedStringRef attrString;
160 str = c2mac(lines[i]);
162 // See https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW2
163 attrs = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys,
164 (const void**)&values, sizeof(keys) / sizeof(keys[0]),
165 &kCFTypeDictionaryKeyCallBacks,
166 &kCFTypeDictionaryValueCallBacks);
167 attrString = CFAttributedStringCreate(kCFAllocatorDefault, str, attrs);
171 line = CTLineCreateWithAttributedString(attrString);
172 r = CTLineGetImageBounds(line, ctxt);
173 r.size.width += r.origin.x;
174 r.size.height += r.origin.y;
177 // fprint(2, "%s: %g %g %g %g\n", lines[i], r.origin.x, r.origin.y, r.size.width, r.size.height);
181 if(bbox.origin.x > r.origin.x)
182 bbox.origin.x = r.origin.x;
183 if(bbox.origin.y > r.origin.y)
184 bbox.origin.y = r.origin.y;
185 if(bbox.size.width < r.size.width)
186 bbox.size.width = r.size.width;
187 if(bbox.size.height < r.size.height)
188 bbox.size.height = r.size.height;
191 bbox.size.width -= bbox.origin.x;
192 bbox.size.height -= bbox.origin.y;
194 *height = bbox.size.height + 0.999999;
195 *ascent = *height - (-bbox.origin.y + 0.999999);
197 CGContextRelease(ctxt);
210 // compute height and ascent for each size on demand
211 f->loadheight = fontheight;
213 // enable all Unicode ranges
214 if(nelem(f->file) > 0xffff)
215 sysfatal("too many subfiles"); // f->file holds ushorts
216 for(i=0; i<nelem(f->range); i++) {
224 mksubfont(XFont *f, char *name, int lo, int hi, int size, int antialias)
227 CGColorSpaceRef color;
230 CTFontDescriptorRef desc;
232 Memimage *m, *mc, *m1;
234 int i, height, ascent;
237 CGFloat blackf[] = { 0.0, 1.0 };
241 desc = CTFontDescriptorCreateWithNameAndSize(s, size);
245 font = CTFontCreateWithFontDescriptor(desc, 0, nil);
250 bbox = CTFontGetBoundingBox(font);
251 x = (int)(bbox.size.width*2 + 0.99999999);
253 fontheight(f, size, &height, &ascent);
255 y0 = height - ascent;
257 m = allocmemimage(Rect(0, 0, x*(hi+1-lo)+1, y+1), GREY8);
260 mc = allocmemimage(Rect(0, 0, x+1, y+1), GREY8);
265 memfillcolor(m, DBlack);
266 memfillcolor(mc, DBlack);
267 fc = malloc((hi+2 - lo) * sizeof fc[0]);
268 sf = malloc(sizeof *sf);
269 if(fc == nil || sf == nil) {
278 color = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
279 ctxt = CGBitmapContextCreate(byteaddr(mc, mc->r.min), Dx(mc->r), Dy(mc->r), 8,
280 mc->width*sizeof(u32int), color, kCGImageAlphaNone);
281 black = CGColorCreate(color, blackf);
282 CGColorSpaceRelease(color);
291 CGContextSetAllowsAntialiasing(ctxt, antialias);
292 CGContextSetTextPosition(ctxt, 0, 0); // XXX
293 #if OSX_VERSION >= 101400
294 CGContextSetAllowsFontSmoothing(ctxt, false);
298 for(i=lo; i<=hi; i++, fc++) {
301 CFDictionaryRef attrs;
302 CFAttributedStringRef attrString;
306 CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
307 CFTypeRef values[] = { font, black };
309 sprint(buf, "%C", (Rune)mapUnicode(name, i));
312 // See https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW2
313 attrs = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys,
314 (const void**)&values, sizeof(keys) / sizeof(keys[0]),
315 &kCFTypeDictionaryKeyCallBacks,
316 &kCFTypeDictionaryValueCallBacks);
317 attrString = CFAttributedStringCreate(kCFAllocatorDefault, str, attrs);
321 line = CTLineCreateWithAttributedString(attrString);
322 CGContextSetTextPosition(ctxt, 0, y0);
323 r = CTLineGetImageBounds(line, ctxt);
324 memfillcolor(mc, DWhite);
325 CTLineDraw(line, ctxt);
330 fc->bottom = Dy(m->r);
332 // fprint(2, "printed %#x: %g %g\n", mapUnicode(i), p1.x, p1.y);
333 p1 = CGContextGetTextPosition(ctxt);
334 if(p1.x <= 0 || mapUnicode(name, i) == 0xfffd) {
338 drawpjw(m, fc, x, (int)(bbox.size.width + 0.99999999), y, y - y0);
345 memimagedraw(m, Rect(x, 0, x + p1.x, y), mc, ZP, memopaque, ZP, S);
352 // round up to 32-bit boundary
353 // so that in-memory data is same
354 // layout as in-file data.
363 m1 = allocmemimage(Rect(0, 0, x, y), antialias ? GREY8 : GREY1);
364 memimagedraw(m1, m1->r, m, m->r.min, memopaque, ZP, S);
370 sf->height = Dy(m1->r);
371 sf->ascent = Dy(m1->r) - y0;