Blob


1 #include <u.h>
3 #define Point OSXPoint
4 #define Rect OSXRect
5 #define Cursor OSXCursor
6 #include <Carbon/Carbon.h>
7 #undef Rect
8 #undef Point
9 #undef Cursor
10 #undef offsetof
11 #undef nil
13 #include <libc.h>
14 #include <draw.h>
15 #include <memdraw.h>
16 #include "a.h"
19 extern void CGFontGetGlyphsForUnichars(CGFontRef, const UniChar[], const CGGlyph[], size_t);
21 char*
22 mac2c(CFStringRef s)
23 {
24 char *p;
25 int n;
27 n = CFStringGetLength(s)*8;
28 p = malloc(n);
29 CFStringGetCString(s, p, n, kCFStringEncodingUTF8);
30 return p;
31 }
33 CFStringRef
34 c2mac(char *p)
35 {
36 return CFStringCreateWithBytes(nil, (uchar*)p, strlen(p), kCFStringEncodingUTF8, false);
37 }
39 Rectangle
40 mac2r(CGRect r, int size, int unit)
41 {
42 Rectangle rr;
44 rr.min.x = r.origin.x*size/unit;
45 rr.min.y = r.origin.y*size/unit;
46 rr.max.x = (r.origin.x+r.size.width)*size/unit + 0.99999999;
47 rr.max.y = (r.origin.x+r.size.width)*size/unit + 0.99999999;
48 return rr;
49 }
51 void
52 loadfonts(void)
53 {
54 int i, n;
55 CTFontCollectionRef allc;
56 CFArrayRef array;
57 CFStringRef s;
58 CTFontDescriptorRef f;
60 allc = CTFontCollectionCreateFromAvailableFonts(0);
61 array = CTFontCollectionCreateMatchingFontDescriptors(allc);
62 n = CFArrayGetCount(array);
63 xfont = emalloc9p(n*sizeof xfont[0]);
64 for(i=0; i<n; i++) {
65 f = (void*)CFArrayGetValueAtIndex(array, i);
66 if(f == nil)
67 continue;
68 s = CTFontDescriptorCopyAttribute(f, kCTFontNameAttribute);
69 xfont[nxfont].name = mac2c(s);
70 CFRelease(s);
71 nxfont++;
72 }
73 }
75 CGRect
76 subfontbbox(CGFontRef font, int lo, int hi)
77 {
78 int i, first;
79 CGRect bbox;
81 bbox.origin.x = 0;
82 bbox.origin.y = 0;
83 bbox.size.height = 0;
84 bbox.size.width = 0;
86 first = 1;
87 for(i=lo; i<=hi; i++) {
88 UniChar u;
89 CGGlyph g;
90 CGRect r;
92 u = i;
93 CGFontGetGlyphsForUnichars(font, &u, &g, 1);
94 if(g == 0 || !CGFontGetGlyphBBoxes(font, &g, 1, &r))
95 continue;
97 r.size.width += r.origin.x;
98 r.size.height += r.origin.y;
99 if(first) {
100 bbox = r;
101 first = 0;
102 continue;
104 if(bbox.origin.x > r.origin.x)
105 bbox.origin.x = r.origin.x;
106 if(bbox.origin.y > r.origin.y)
107 bbox.origin.y = r.origin.y;
108 if(bbox.size.width < r.size.width)
109 bbox.size.width = r.size.width;
110 if(bbox.size.height < r.size.height)
111 bbox.size.height = r.size.height;
114 bbox.size.width -= bbox.origin.x;
115 bbox.size.height -= bbox.origin.y;
116 return bbox;
119 void
120 load(XFont *f)
122 int i, j;
123 CGFontRef font;
124 CFStringRef s;
125 UniChar u[256];
126 CGGlyph g[256];
127 CGRect bbox;
129 if(f->loaded)
130 return;
131 f->loaded = 1;
132 s = c2mac(f->name);
133 font = CGFontCreateWithFontName(s);
134 CFRelease(s);
135 if(font == nil)
136 return;
138 // assume bbox gives latin1 is height/ascent for all
139 bbox = subfontbbox(font, 0x00, 0xff);
140 f->unit = CGFontGetUnitsPerEm(font);
141 f->height = bbox.size.height;
142 f->originy = bbox.origin.y;
144 // figure out where the letters are
145 for(i=0; i<0xffff; i+=0x100) {
146 for(j=0; j<0x100; j++) {
147 u[j] = i+j;
148 g[j] = 0;
150 CGFontGetGlyphsForUnichars(font, u, g, 256);
151 for(j=0; j<0x100; j++) {
152 if(g[j] != 0) {
153 f->range[i>>8] = 1;
154 f->nrange++;
155 break;
159 CFRelease(font);
162 Memsubfont*
163 mksubfont(char *name, int lo, int hi, int size, int antialias)
165 CFStringRef s;
166 CGColorSpaceRef color;
167 CGContextRef ctxt;
168 CGFontRef font;
169 CGRect bbox;
170 Memimage *m, *mc, *m1;
171 int x, y, y0;
172 int i, unit;
173 Fontchar *fc, *fc0;
174 Memsubfont *sf;
176 s = c2mac(name);
177 font = CGFontCreateWithFontName(s);
178 CFRelease(s);
179 if(font == nil)
180 return nil;
181 bbox = subfontbbox(font, lo, hi);
182 unit = CGFontGetUnitsPerEm(font);
183 x = (int)(bbox.size.width * size / unit + 0.99999999);
184 y = bbox.size.height * size/unit + 0.99999999;
185 y0 = (int)(-bbox.origin.y * size/unit + 0.99999999);
186 m = allocmemimage(Rect(0, 0, x*(hi+1-lo), y), GREY8);
187 if(m == nil)
188 return nil;
189 mc = allocmemimage(Rect(0, 0, x, y), GREY8);
190 if(mc == nil)
191 return nil;
192 memfillcolor(m, DBlack);
193 memfillcolor(mc, DBlack);
194 fc = malloc((hi+2 - lo) * sizeof fc[0]);
195 sf = malloc(sizeof *sf);
196 if(fc == nil || sf == nil) {
197 freememimage(m);
198 freememimage(mc);
199 free(fc);
200 free(sf);
201 return nil;
203 fc0 = fc;
205 color = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
206 ctxt = CGBitmapContextCreate(byteaddr(mc, mc->r.min), Dx(mc->r), Dy(mc->r), 8,
207 mc->width*sizeof(u32int), color, kCGImageAlphaNone);
208 CGColorSpaceRelease(color);
209 if(ctxt == nil) {
210 freememimage(m);
211 freememimage(mc);
212 free(fc);
213 free(sf);
214 return nil;
217 CGContextSetFont(ctxt, font);
218 CGContextSetFontSize(ctxt, size);
219 CGContextSetAllowsAntialiasing(ctxt, antialias);
220 CGContextSetRGBFillColor(ctxt, 1, 1, 1, 1);
221 CGContextSetTextPosition(ctxt, 0, 0); // XXX
223 x = 0;
224 for(i=lo; i<=hi; i++, fc++) {
225 UniChar u[2];
226 CGGlyph g[2];
227 CGRect r[2];
228 CGPoint p1;
229 int n;
231 fc->x = x;
232 fc->top = 0;
233 fc->bottom = Dy(m->r);
235 n = 0;
236 u[n++] = i;
237 if(0) // debugging
238 u[n++] = '|';
239 g[0] = 0;
240 CGFontGetGlyphsForUnichars(font, u, g, n);
241 if(g[0] == 0 || !CGFontGetGlyphBBoxes(font, g, n, r)) {
242 None:
243 fc->width = 0;
244 if(i == 0) {
245 Point p;
246 Fontchar *i;
247 p = Pt(x, y0);
248 // memimagestring(m, p, memwhite, ZP, defont, peterface);
249 i = defont->info + 0;
250 memdraw(m, Rect(p.x+i->left, p.y+i->top, p.x+i->left+(i[1].x-i[0].x), p.y+i->bottom),
251 memwhite, ZP, defont->bits, Pt(i->x, i->top), S);
252 p.x += i->width;
253 fc->left = i->left;
254 fc->width = i->width;
255 x = p.x;
257 continue;
259 memfillcolor(mc, DBlack);
260 CGContextSetTextPosition(ctxt, 0, y0);
261 CGContextShowGlyphs(ctxt, g, n);
262 p1 = CGContextGetTextPosition(ctxt);
263 if(p1.x <= 0)
264 goto None;
265 memimagedraw(m, Rect(x, 0, x + p1.x, y), mc, ZP, memopaque, ZP, S);
266 fc->width = p1.x;
267 fc->left = 0;
268 x += p1.x;
270 fc->x = x;
272 // round up to 32-bit boundary
273 // so that in-memory data is same
274 // layout as in-file data.
275 if(antialias)
276 x += -x & 3;
277 else
278 x += -x & 31;
279 m1 = allocmemimage(Rect(0, 0, x, y), antialias ? GREY8 : GREY1);
280 memimagedraw(m1, m1->r, m, m->r.min, memopaque, ZP, S);
281 freememimage(m);
283 sf->name = nil;
284 sf->n = hi+1 - lo;
285 sf->height = Dy(m1->r);
286 sf->ascent = Dy(m1->r) - y0;
287 sf->info = fc0;
288 sf->bits = m1;
290 return sf;