aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@swtch.com>2015-02-16 23:58:22 -0500
committerRuss Cox <rsc@swtch.com>2015-02-17 05:00:09 +0000
commit32dc15fa62d94c88f0b62bfe4d64ba60fe1733a6 (patch)
tree4cf16da305ff7a0b30b0896a6ff79b0e9ea65bac /src
parent5d86ecd4b7fd8bccc88a06803c7f8ace26a88788 (diff)
downloadplan9port-32dc15fa62d94c88f0b62bfe4d64ba60fe1733a6.tar.gz
plan9port-32dc15fa62d94c88f0b62bfe4d64ba60fe1733a6.tar.bz2
plan9port-32dc15fa62d94c88f0b62bfe4d64ba60fe1733a6.zip
fontsrv: use CoreText API on OS X
This gets us font fallback for free and avoids use of a deprecated API that might go away some day. Change-Id: I4b9b1a1ce3e6d98bfb407e3baea13f4adfe2c26a Reviewed-on: https://plan9port-review.googlesource.com/1160 Reviewed-by: Russ Cox <rsc@swtch.com>
Diffstat (limited to 'src')
-rw-r--r--src/cmd/fontsrv/a.h3
-rw-r--r--src/cmd/fontsrv/main.c18
-rw-r--r--src/cmd/fontsrv/nowsys.c2
-rw-r--r--src/cmd/fontsrv/osx.c213
-rw-r--r--src/cmd/fontsrv/x11.c13
5 files changed, 143 insertions, 106 deletions
diff --git a/src/cmd/fontsrv/a.h b/src/cmd/fontsrv/a.h
index ffe46ae6..67a7b365 100644
--- a/src/cmd/fontsrv/a.h
+++ b/src/cmd/fontsrv/a.h
@@ -11,6 +11,7 @@ struct XFont
int unit;
double height;
double originy;
+ void (*loadheight)(XFont*, int, int*, int*);
// fontconfig workarround, as FC_FULLNAME does not work for matching fonts.
char *fontfile;
@@ -19,7 +20,7 @@ struct XFont
void loadfonts(void);
void load(XFont*);
-Memsubfont* mksubfont(char*, int, int, int, int);
+Memsubfont* mksubfont(XFont*, char*, int, int, int, int);
extern XFont *xfont;
extern int nxfont;
diff --git a/src/cmd/fontsrv/main.c b/src/cmd/fontsrv/main.c
index 93eb39e2..5a43ef15 100644
--- a/src/cmd/fontsrv/main.c
+++ b/src/cmd/fontsrv/main.c
@@ -144,7 +144,7 @@ xwalk1(Fid *fid, char *name, Qid *qid)
switch(QTYPE(path)) {
default:
NotFound:
- return "file not found";
+ return "file not found";
case Qroot:
if(dotdot)
@@ -313,10 +313,18 @@ xread(Req *r)
fmtstrinit(&fmt);
f = &xfont[QFONT(path)];
load(f);
- if(f->unit == 0)
+ if(f->unit == 0 && f->loadheight == nil) {
+ readstr(r, "font missing\n");
break;
- height = f->height * (int)QSIZE(path)/f->unit + 0.99999999;
- ascent = height - (int)(-f->originy * (int)QSIZE(path)/f->unit + 0.99999999);
+ }
+ height = 0;
+ ascent = 0;
+ if(f->unit > 0) {
+ height = f->height * (int)QSIZE(path)/f->unit + 0.99999999;
+ ascent = height - (int)(-f->originy * (int)QSIZE(path)/f->unit + 0.99999999);
+ }
+ if(f->loadheight != nil)
+ f->loadheight(f, QSIZE(path), &height, &ascent);
fmtprint(&fmt, "%11d %11d\n", height, ascent);
for(i=0; i<nelem(f->range); i++) {
if(f->range[i] == 0)
@@ -331,7 +339,7 @@ xread(Req *r)
f = &xfont[QFONT(path)];
load(f);
if(r->fid->aux == nil) {
- r->fid->aux = mksubfont(f->name, QRANGE(path)<<8, (QRANGE(path)<<8)+0xFF, QSIZE(path), QANTIALIAS(path));
+ r->fid->aux = mksubfont(f, f->name, QRANGE(path)<<8, (QRANGE(path)<<8)+0xFF, QSIZE(path), QANTIALIAS(path));
if(r->fid->aux == nil) {
responderrstr(r);
return;
diff --git a/src/cmd/fontsrv/nowsys.c b/src/cmd/fontsrv/nowsys.c
index eb3b57a9..86610bd1 100644
--- a/src/cmd/fontsrv/nowsys.c
+++ b/src/cmd/fontsrv/nowsys.c
@@ -15,7 +15,7 @@ load(XFont *f)
}
Memsubfont*
-mksubfont(char *name, int lo, int hi, int size, int antialias)
+mksubfont(XFont *f, char *name, int lo, int hi, int size, int antialias)
{
return nil;
}
diff --git a/src/cmd/fontsrv/osx.c b/src/cmd/fontsrv/osx.c
index a35eb4a5..2c88fd55 100644
--- a/src/cmd/fontsrv/osx.c
+++ b/src/cmd/fontsrv/osx.c
@@ -15,7 +15,6 @@
#include <memdraw.h>
#include "a.h"
-
extern void CGFontGetGlyphsForUnichars(CGFontRef, const UniChar[], const CGGlyph[], size_t);
int
@@ -84,35 +83,73 @@ loadfonts(void)
}
}
-CGRect
-subfontbbox(CGFontRef font, int lo, int hi)
+// Some representative text to try to discern line heights.
+static char *lines[] = {
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ "abcdefghijklmnopqrstuvwxyz",
+ "g",
+ "ὕαλον ϕαγεῖν δύναμαι· τοῦτο οὔ με βλάπτει.",
+ "私はガラスを食べられます。それは私を傷つけません。",
+ "Aš galiu valgyti stiklą ir jis manęs nežeidžia",
+ "Môžem jesť sklo. Nezraní ma.",
+};
+
+static void
+fontheight(XFont *f, int size, int *height, int *ascent)
{
- int i, first;
+ int i;
+ CFStringRef s;
CGRect bbox;
+ CTFontRef font;
+ CTFontDescriptorRef desc;
+ CGContextRef ctxt;
+ CGColorSpaceRef color;
+
+ s = c2mac(f->name);
+ desc = CTFontDescriptorCreateWithNameAndSize(s, size);
+ CFRelease(s);
+ if(desc == nil)
+ return;
+ font = CTFontCreateWithFontDescriptor(desc, 0, nil);
+ CFRelease(desc);
+ if(font == nil)
+ return;
- bbox.origin.x = 0;
- bbox.origin.y = 0;
- bbox.size.height = 0;
- bbox.size.width = 0;
+ color = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
+ ctxt = CGBitmapContextCreate(nil, 1, 1, 8, 1, color, kCGImageAlphaNone);
+ CGColorSpaceRelease(color);
+ CGContextSetTextPosition(ctxt, 0, 0);
- first = 1;
- for(i=lo; i<=hi; i++) {
- UniChar u;
- CGGlyph g;
+ for(i=0; i<nelem(lines); i++) {
+ CFStringRef keys[] = { kCTFontAttributeName };
+ CFTypeRef values[] = { font };
+ CFStringRef str;
+ CFDictionaryRef attrs;
+ CFAttributedStringRef attrString;
CGRect r;
+ CTLineRef line;
- u = mapUnicode(i);
- CGFontGetGlyphsForUnichars(font, &u, &g, 1);
- if(g == 0 || !CGFontGetGlyphBBoxes(font, &g, 1, &r))
- continue;
+ str = c2mac(lines[i]);
+
+ // See https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW2
+ attrs = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys,
+ (const void**)&values, sizeof(keys) / sizeof(keys[0]),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ attrString = CFAttributedStringCreate(kCFAllocatorDefault, str, attrs);
+ CFRelease(str);
+ CFRelease(attrs);
+ line = CTLineCreateWithAttributedString(attrString);
+ r = CTLineGetImageBounds(line, ctxt);
r.size.width += r.origin.x;
r.size.height += r.origin.y;
- if(first) {
+ CFRelease(line);
+
+// fprint(2, "%s: %g %g %g %g\n", lines[i], r.origin.x, r.origin.y, r.size.width, r.size.height);
+
+ if(i == 0)
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)
@@ -122,79 +159,71 @@ subfontbbox(CGFontRef font, int lo, int hi)
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;
+
+ *height = bbox.size.height + 0.999999;
+ *ascent = *height - (-bbox.origin.y + 0.999999);
+
+ CGContextRelease(ctxt);
+ CFRelease(font);
}
void
load(XFont *f)
{
- int i, j;
- CGFontRef font;
- CFStringRef s;
- UniChar u[256];
- CGGlyph g[256];
- CGRect bbox;
+ int i;
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] = mapUnicode(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;
- }
- }
+
+ // compute height and ascent for each size on demand
+ f->loadheight = fontheight;
+
+ // enable all Unicode ranges
+ for(i=0; i<nelem(f->range); i++) {
+ f->range[i] = 1;
+ f->nrange++;
}
- CFRelease(font);
}
Memsubfont*
-mksubfont(char *name, int lo, int hi, int size, int antialias)
+mksubfont(XFont *f, char *name, int lo, int hi, int size, int antialias)
{
CFStringRef s;
CGColorSpaceRef color;
CGContextRef ctxt;
- CGFontRef font;
+ CTFontRef font;
+ CTFontDescriptorRef desc;
CGRect bbox;
Memimage *m, *mc, *m1;
int x, y, y0;
- int i, unit;
+ int i, height, ascent;
Fontchar *fc, *fc0;
Memsubfont *sf;
+ CGFloat whitef[] = { 1.0, 1.0 };
+ CGColorRef white;
s = c2mac(name);
- font = CGFontCreateWithFontName(s);
+ desc = CTFontDescriptorCreateWithNameAndSize(s, size);
CFRelease(s);
+ if(desc == nil)
+ return nil;
+ font = CTFontCreateWithFontDescriptor(desc, 0, nil);
+ CFRelease(desc);
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);
+
+
+ bbox = CTFontGetBoundingBox(font);
+ x = (int)(bbox.size.width + 0.99999999);
+
+ fontheight(f, size, &height, &ascent);
+ y = height;
+ y0 = height - ascent;
+
m = allocmemimage(Rect(0, 0, x*(hi+1-lo)+1, y+1), GREY8);
if(m == nil)
return nil;
@@ -217,6 +246,7 @@ mksubfont(char *name, int lo, int hi, int size, int antialias)
color = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
ctxt = CGBitmapContextCreate(byteaddr(mc, mc->r.min), Dx(mc->r), Dy(mc->r), 8,
mc->width*sizeof(u32int), color, kCGImageAlphaNone);
+ white = CGColorCreate(color, whitef);
CGColorSpaceRelease(color);
if(ctxt == nil) {
freememimage(m);
@@ -226,46 +256,56 @@ mksubfont(char *name, int lo, int hi, int size, int antialias)
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];
+ char buf[20];
+ CFStringRef str;
+ CFDictionaryRef attrs;
+ CFAttributedStringRef attrString;
+ CTLineRef line;
+ CGRect r;
CGPoint p1;
- int n;
+ CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
+ CFTypeRef values[] = { font, white };
+
+ sprint(buf, "%C", (Rune)mapUnicode(i));
+ str = c2mac(buf);
+
+ // See https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW2
+ attrs = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys,
+ (const void**)&values, sizeof(keys) / sizeof(keys[0]),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ attrString = CFAttributedStringCreate(kCFAllocatorDefault, str, attrs);
+ CFRelease(str);
+ CFRelease(attrs);
+
+ line = CTLineCreateWithAttributedString(attrString);
+ CGContextSetTextPosition(ctxt, 0, y0);
+ r = CTLineGetImageBounds(line, ctxt);
+ memfillcolor(mc, DBlack);
+ CTLineDraw(line, ctxt);
+ CFRelease(line);
fc->x = x;
fc->top = 0;
fc->bottom = Dy(m->r);
- n = 0;
- u[n++] = mapUnicode(i);
- if(0) // debugging
- u[n++] = '|';
- g[0] = 0;
- CGFontGetGlyphsForUnichars(font, u, g, n);
- if(g[0] == 0 || !CGFontGetGlyphBBoxes(font, g, n, r)) {
- None:
+// fprint(2, "printed %#x: %g %g\n", mapUnicode(i), p1.x, p1.y);
+ p1 = CGContextGetTextPosition(ctxt);
+ if(p1.x <= 0 || mapUnicode(i) == 0xfffd) {
fc->width = 0;
fc->left = 0;
if(i == 0) {
- drawpjw(m, fc, x, (int)(bbox.size.width * size / unit + 0.99999999), y, y - y0);
+ drawpjw(m, fc, x, (int)(bbox.size.width + 0.99999999), y, y - y0);
x += fc->width;
}
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;
@@ -297,4 +337,3 @@ mksubfont(char *name, int lo, int hi, int size, int antialias)
return sf;
}
-
diff --git a/src/cmd/fontsrv/x11.c b/src/cmd/fontsrv/x11.c
index 43b013e3..c7acaeb9 100644
--- a/src/cmd/fontsrv/x11.c
+++ b/src/cmd/fontsrv/x11.c
@@ -102,7 +102,7 @@ load(XFont *f)
}
Memsubfont*
-mksubfont(char *name, int lo, int hi, int size, int antialias)
+mksubfont(XFont *xf, char *name, int lo, int hi, int size, int antialias)
{
XFont *xf, *xfp, *xfe;
FT_Face face;
@@ -115,17 +115,6 @@ mksubfont(char *name, int lo, int hi, int size, int antialias)
Memsubfont *sf;
//Point rect_points[4];
- xf = nil;
- for(xfp=xfont, xfe=xfont+nxfont; xfp != xfe; xfp++) {
- if(strcmp(xfp->name, name) == 0) {
- xf = xfp;
- break;
- }
- }
-
- if(!xf)
- return nil;
-
e = FT_New_Face(lib, xf->fontfile, xf->index, &face);
if(e){