aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/fontsrv/osx.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/fontsrv/osx.c')
-rw-r--r--src/cmd/fontsrv/osx.c292
1 files changed, 292 insertions, 0 deletions
diff --git a/src/cmd/fontsrv/osx.c b/src/cmd/fontsrv/osx.c
new file mode 100644
index 00000000..94190d19
--- /dev/null
+++ b/src/cmd/fontsrv/osx.c
@@ -0,0 +1,292 @@
+#include <u.h>
+
+#define Point OSXPoint
+#define Rect OSXRect
+#define Cursor OSXCursor
+#include <Carbon/Carbon.h>
+#undef Rect
+#undef Point
+#undef Cursor
+#undef offsetof
+#undef nil
+
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+#include "a.h"
+
+
+extern void CGFontGetGlyphsForUnichars(CGFontRef, const UniChar[], const CGGlyph[], size_t);
+
+char*
+mac2c(CFStringRef s)
+{
+ char *p;
+ int n;
+
+ n = CFStringGetLength(s)*8;
+ p = malloc(n);
+ CFStringGetCString(s, p, n, kCFStringEncodingUTF8);
+ return p;
+}
+
+CFStringRef
+c2mac(char *p)
+{
+ return CFStringCreateWithBytes(nil, (uchar*)p, strlen(p), kCFStringEncodingUTF8, false);
+}
+
+Rectangle
+mac2r(CGRect r, int size, int unit)
+{
+ Rectangle rr;
+
+ rr.min.x = r.origin.x*size/unit;
+ rr.min.y = r.origin.y*size/unit;
+ rr.max.x = (r.origin.x+r.size.width)*size/unit + 0.99999999;
+ rr.max.y = (r.origin.x+r.size.width)*size/unit + 0.99999999;
+ return rr;
+}
+
+void
+loadfonts(void)
+{
+ int i, n;
+ CTFontCollectionRef allc;
+ CFArrayRef array;
+ CFStringRef s;
+ CTFontDescriptorRef f;
+
+ allc = CTFontCollectionCreateFromAvailableFonts(0);
+ array = CTFontCollectionCreateMatchingFontDescriptors(allc);
+ n = CFArrayGetCount(array);
+ xfont = emalloc9p(n*sizeof xfont[0]);
+ for(i=0; i<n; i++) {
+ f = (void*)CFArrayGetValueAtIndex(array, i);
+ if(f == nil)
+ continue;
+ s = CTFontDescriptorCopyAttribute(f, kCTFontNameAttribute);
+ xfont[nxfont].name = mac2c(s);
+ CFRelease(s);
+ nxfont++;
+ }
+}
+
+CGRect
+subfontbbox(CGFontRef font, int lo, int hi)
+{
+ int i, first;
+ CGRect bbox;
+
+ bbox.origin.x = 0;
+ bbox.origin.y = 0;
+ bbox.size.height = 0;
+ bbox.size.width = 0;
+
+ first = 1;
+ for(i=lo; i<=hi; i++) {
+ UniChar u;
+ CGGlyph g;
+ CGRect r;
+
+ u = i;
+ CGFontGetGlyphsForUnichars(font, &u, &g, 1);
+ if(g == 0 || !CGFontGetGlyphBBoxes(font, &g, 1, &r))
+ continue;
+
+ r.size.width += r.origin.x;
+ r.size.height += r.origin.y;
+ if(first) {
+ bbox = r;
+ first = 0;
+ continue;
+ }
+ if(bbox.origin.x > r.origin.x)
+ bbox.origin.x = r.origin.x;
+ if(bbox.origin.y > r.origin.y)
+ bbox.origin.y = r.origin.y;
+ if(bbox.size.width < r.size.width)
+ bbox.size.width = r.size.width;
+ if(bbox.size.height < r.size.height)
+ bbox.size.height = r.size.height;
+ }
+
+ bbox.size.width -= bbox.origin.x;
+ bbox.size.height -= bbox.origin.y;
+ return bbox;
+}
+
+void
+load(XFont *f)
+{
+ int i, j;
+ CGFontRef font;
+ CFStringRef s;
+ UniChar u[256];
+ CGGlyph g[256];
+ CGRect bbox;
+
+ if(f->loaded)
+ return;
+ f->loaded = 1;
+ s = c2mac(f->name);
+ font = CGFontCreateWithFontName(s);
+ CFRelease(s);
+ if(font == nil)
+ return;
+
+ // assume bbox gives latin1 is height/ascent for all
+ bbox = subfontbbox(font, 0x00, 0xff);
+ f->unit = CGFontGetUnitsPerEm(font);
+ f->height = bbox.size.height;
+ f->originy = bbox.origin.y;
+
+ // figure out where the letters are
+ for(i=0; i<0xffff; i+=0x100) {
+ for(j=0; j<0x100; j++) {
+ u[j] = i+j;
+ g[j] = 0;
+ }
+ CGFontGetGlyphsForUnichars(font, u, g, 256);
+ for(j=0; j<0x100; j++) {
+ if(g[j] != 0) {
+ f->range[i>>8] = 1;
+ f->nrange++;
+ break;
+ }
+ }
+ }
+ CFRelease(font);
+}
+
+Memsubfont*
+mksubfont(char *name, int lo, int hi, int size, int antialias)
+{
+ CFStringRef s;
+ CGColorSpaceRef color;
+ CGContextRef ctxt;
+ CGFontRef font;
+ CGRect bbox;
+ Memimage *m, *mc, *m1;
+ int x, y, y0;
+ int i, unit;
+ Fontchar *fc, *fc0;
+ Memsubfont *sf;
+
+ s = c2mac(name);
+ font = CGFontCreateWithFontName(s);
+ CFRelease(s);
+ if(font == nil)
+ return nil;
+ bbox = subfontbbox(font, lo, hi);
+ unit = CGFontGetUnitsPerEm(font);
+ x = (int)(bbox.size.width * size / unit + 0.99999999);
+ y = bbox.size.height * size/unit + 0.99999999;
+ y0 = (int)(-bbox.origin.y * size/unit + 0.99999999);
+ m = allocmemimage(Rect(0, 0, x*(hi+1-lo), y), GREY8);
+ if(m == nil)
+ return nil;
+ mc = allocmemimage(Rect(0, 0, x, y), GREY8);
+ if(mc == nil)
+ return nil;
+ memfillcolor(m, DBlack);
+ memfillcolor(mc, DBlack);
+ fc = malloc((hi+2 - lo) * sizeof fc[0]);
+ sf = malloc(sizeof *sf);
+ if(fc == nil || sf == nil) {
+ freememimage(m);
+ freememimage(mc);
+ free(fc);
+ free(sf);
+ return nil;
+ }
+ fc0 = fc;
+
+ color = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
+ ctxt = CGBitmapContextCreate(byteaddr(mc, mc->r.min), Dx(mc->r), Dy(mc->r), 8,
+ mc->width*sizeof(u32int), color, kCGImageAlphaNone);
+ CGColorSpaceRelease(color);
+ if(ctxt == nil) {
+ freememimage(m);
+ freememimage(mc);
+ free(fc);
+ free(sf);
+ return nil;
+ }
+
+ CGContextSetFont(ctxt, font);
+ CGContextSetFontSize(ctxt, size);
+ CGContextSetAllowsAntialiasing(ctxt, antialias);
+ CGContextSetRGBFillColor(ctxt, 1, 1, 1, 1);
+ CGContextSetTextPosition(ctxt, 0, 0); // XXX
+
+ x = 0;
+ for(i=lo; i<=hi; i++, fc++) {
+ UniChar u[2];
+ CGGlyph g[2];
+ CGRect r[2];
+ CGPoint p1;
+ int n;
+
+ fc->x = x;
+ fc->top = 0;
+ fc->bottom = Dy(m->r);
+
+ n = 0;
+ u[n++] = i;
+ if(0) // debugging
+ u[n++] = '|';
+ g[0] = 0;
+ CGFontGetGlyphsForUnichars(font, u, g, n);
+ if(g[0] == 0 || !CGFontGetGlyphBBoxes(font, g, n, r)) {
+ None:
+ fc->width = 0;
+ if(i == 0) {
+ Point p;
+ Fontchar *i;
+ p = Pt(x, y0);
+ // memimagestring(m, p, memwhite, ZP, defont, peterface);
+ i = defont->info + 0;
+ 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),
+ memwhite, ZP, defont->bits, Pt(i->x, i->top), S);
+ p.x += i->width;
+ fc->left = i->left;
+ fc->width = i->width;
+ x = p.x;
+ }
+ continue;
+ }
+ memfillcolor(mc, DBlack);
+ CGContextSetTextPosition(ctxt, 0, y0);
+ CGContextShowGlyphs(ctxt, g, n);
+ p1 = CGContextGetTextPosition(ctxt);
+ if(p1.x <= 0)
+ goto None;
+ memimagedraw(m, Rect(x, 0, x + p1.x, y), mc, ZP, memopaque, ZP, S);
+ fc->width = p1.x;
+ fc->left = 0;
+ x += p1.x;
+ }
+ fc->x = x;
+
+ // round up to 32-bit boundary
+ // so that in-memory data is same
+ // layout as in-file data.
+ if(antialias)
+ x += -x & 3;
+ else
+ x += -x & 31;
+ m1 = allocmemimage(Rect(0, 0, x, y), antialias ? GREY8 : GREY1);
+ memimagedraw(m1, m1->r, m, m->r.min, memopaque, ZP, S);
+ freememimage(m);
+
+ sf->name = nil;
+ sf->n = hi+1 - lo;
+ sf->height = Dy(m1->r);
+ sf->ascent = Dy(m1->r) - y0;
+ sf->info = fc0;
+ sf->bits = m1;
+
+ return sf;
+}
+