devdraw: use consistent mac-* prefix on macOS files
We were using osx- and cocoa- but it's not even OS X anymore.
This commit is contained in:
362
src/cmd/fontsrv/mac.c
Normal file
362
src/cmd/fontsrv/mac.c
Normal file
@@ -0,0 +1,362 @@
|
||||
#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);
|
||||
|
||||
// In these fonts, it's too hard to distinguish U+2018 and U+2019,
|
||||
// so don't map the ASCII quotes there.
|
||||
// See https://github.com/9fans/plan9port/issues/86
|
||||
static char *skipquotemap[] = {
|
||||
"Courier",
|
||||
"Osaka",
|
||||
};
|
||||
|
||||
int
|
||||
mapUnicode(char *name, int i)
|
||||
{
|
||||
int j;
|
||||
|
||||
if(0xd800 <= i && i < 0xe000) // surrogate pairs, will crash OS X libraries!
|
||||
return 0xfffd;
|
||||
for(j=0; j<nelem(skipquotemap); j++) {
|
||||
if(strstr(name, skipquotemap[j]))
|
||||
return i;
|
||||
}
|
||||
switch(i) {
|
||||
case '\'':
|
||||
return 0x2019;
|
||||
case '`':
|
||||
return 0x2018;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
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;
|
||||
|
||||
color = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
|
||||
ctxt = CGBitmapContextCreate(nil, 1, 1, 8, 1, color, kCGImageAlphaNone);
|
||||
CGColorSpaceRelease(color);
|
||||
CGContextSetTextPosition(ctxt, 0, 0);
|
||||
|
||||
for(i=0; i<nelem(lines); i++) {
|
||||
CFStringRef keys[] = { kCTFontAttributeName };
|
||||
CFTypeRef values[] = { font };
|
||||
CFStringRef str;
|
||||
CFDictionaryRef attrs;
|
||||
CFAttributedStringRef attrString;
|
||||
CGRect r;
|
||||
CTLineRef line;
|
||||
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
|
||||
*height = bbox.size.height + 0.999999;
|
||||
*ascent = *height - (-bbox.origin.y + 0.999999);
|
||||
|
||||
CGContextRelease(ctxt);
|
||||
CFRelease(font);
|
||||
}
|
||||
|
||||
void
|
||||
load(XFont *f)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(f->loaded)
|
||||
return;
|
||||
f->loaded = 1;
|
||||
|
||||
// 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++;
|
||||
}
|
||||
}
|
||||
|
||||
Memsubfont*
|
||||
mksubfont(XFont *f, char *name, int lo, int hi, int size, int antialias)
|
||||
{
|
||||
CFStringRef s;
|
||||
CGColorSpaceRef color;
|
||||
CGContextRef ctxt;
|
||||
CTFontRef font;
|
||||
CTFontDescriptorRef desc;
|
||||
CGRect bbox;
|
||||
Memimage *m, *mc, *m1;
|
||||
int x, y, y0;
|
||||
int i, height, ascent;
|
||||
Fontchar *fc, *fc0;
|
||||
Memsubfont *sf;
|
||||
CGFloat whitef[] = { 1.0, 1.0 };
|
||||
CGColorRef white;
|
||||
|
||||
s = c2mac(name);
|
||||
desc = CTFontDescriptorCreateWithNameAndSize(s, size);
|
||||
CFRelease(s);
|
||||
if(desc == nil)
|
||||
return nil;
|
||||
font = CTFontCreateWithFontDescriptor(desc, 0, nil);
|
||||
CFRelease(desc);
|
||||
if(font == nil)
|
||||
return nil;
|
||||
|
||||
|
||||
bbox = CTFontGetBoundingBox(font);
|
||||
x = (int)(bbox.size.width*2 + 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;
|
||||
mc = allocmemimage(Rect(0, 0, x+1, y+1), GREY8);
|
||||
if(mc == nil){
|
||||
freememimage(m);
|
||||
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);
|
||||
white = CGColorCreate(color, whitef);
|
||||
CGColorSpaceRelease(color);
|
||||
if(ctxt == nil) {
|
||||
freememimage(m);
|
||||
freememimage(mc);
|
||||
free(fc);
|
||||
free(sf);
|
||||
return nil;
|
||||
}
|
||||
|
||||
CGContextSetAllowsAntialiasing(ctxt, antialias);
|
||||
CGContextSetTextPosition(ctxt, 0, 0); // XXX
|
||||
#if OSX_VERSION >= 101400
|
||||
CGContextSetAllowsFontSmoothing(ctxt, false);
|
||||
#endif
|
||||
|
||||
x = 0;
|
||||
for(i=lo; i<=hi; i++, fc++) {
|
||||
char buf[20];
|
||||
CFStringRef str;
|
||||
CFDictionaryRef attrs;
|
||||
CFAttributedStringRef attrString;
|
||||
CTLineRef line;
|
||||
CGRect r;
|
||||
CGPoint p1;
|
||||
CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
|
||||
CFTypeRef values[] = { font, white };
|
||||
|
||||
sprint(buf, "%C", (Rune)mapUnicode(name, 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);
|
||||
|
||||
// fprint(2, "printed %#x: %g %g\n", mapUnicode(i), p1.x, p1.y);
|
||||
p1 = CGContextGetTextPosition(ctxt);
|
||||
if(p1.x <= 0 || mapUnicode(name, i) == 0xfffd) {
|
||||
fc->width = 0;
|
||||
fc->left = 0;
|
||||
if(i == 0) {
|
||||
drawpjw(m, fc, x, (int)(bbox.size.width + 0.99999999), y, y - y0);
|
||||
x += fc->width;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
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(x == 0)
|
||||
x = 1;
|
||||
if(y == 0)
|
||||
y = 1;
|
||||
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);
|
||||
freememimage(mc);
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user