plan9port/src/cmd/fontsrv/x11.c
Xiao-Yong c82e11b24e fontsrv: x11 uses FC_POSTSCRIPT_NAME (#174)
This makes fontsrv use the PostScript font names on X11.
The PostScript font names contains only alphanumeric and
hyphens.  This allows us to use the Font command in acme.
It also matches the font names used by fontsrv on macOS,
which has been using PostScript font names.
2018-11-13 23:13:15 -05:00

255 lines
5.6 KiB
C

#include <u.h>
#include <fontconfig/fontconfig.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include "a.h"
static FcConfig *fc;
static FT_Library lib;
static int dpi = 96;
void
loadfonts(void)
{
int i;
FT_Error e;
FcFontSet *sysfonts;
if(!FcInit() || (fc=FcInitLoadConfigAndFonts()) == NULL) {
fprint(2, "fontconfig initialization failed\n");
exits("fontconfig failed");
}
e = FT_Init_FreeType(&lib);
if(e) {
fprint(2, "freetype initialization failed: %d\n", e);
exits("freetype failed");
}
sysfonts = FcConfigGetFonts(fc, FcSetSystem);
xfont = emalloc9p(sysfonts->nfont*sizeof xfont[0]);
memset(xfont, 0, sysfonts->nfont*sizeof xfont[0]);
for(i=0; i<sysfonts->nfont; i++) {
FcChar8 *fullname, *fontfile;
int index;
FcPattern *pat = sysfonts->fonts[i];
if(FcPatternGetString(pat, FC_POSTSCRIPT_NAME, 0, &fullname) != FcResultMatch ||
FcPatternGetString(pat, FC_FILE, 0, &fontfile) != FcResultMatch ||
FcPatternGetInteger(pat, FC_INDEX, 0, &index) != FcResultMatch)
continue;
xfont[nxfont].name = strdup((char*)fullname);
xfont[nxfont].fontfile = strdup((char*)fontfile);
xfont[nxfont].index = index;
nxfont++;
}
FcFontSetDestroy(sysfonts);
}
void
load(XFont *f)
{
FT_Face face;
FT_Error e;
FT_ULong charcode;
FT_UInt glyph_index;
if(f->loaded)
return;
e = FT_New_Face(lib, f->fontfile, f->index, &face);
if(e){
fprint(2, "load failed for %s (%s) index:%d\n", f->name, f->fontfile, f->index);
return;
}
if(!FT_IS_SCALABLE(face)) {
fprint(2, "%s is a non scalable font, skipping\n", f->name);
FT_Done_Face(face);
f->loaded = 1;
return;
}
f->unit = face->units_per_EM;
f->height = (int)((face->ascender - face->descender) * 1.2);
f->originy = face->descender; // bbox.yMin (or descender) is negative, becase the baseline is y-coord 0
for(charcode=FT_Get_First_Char(face, &glyph_index); glyph_index != 0;
charcode=FT_Get_Next_Char(face, charcode, &glyph_index)) {
int idx = charcode/SubfontSize;
if(charcode > 0xffff)
break;
if(!f->range[idx]) {
f->range[idx] = 1;
f->nrange++;
}
}
// libdraw expects U+0000 to be present
if(!f->range[0]) {
f->range[0] = 1;
f->nrange++;
}
FT_Done_Face(face);
f->loaded = 1;
}
Memsubfont*
mksubfont(XFont *xf, char *name, int lo, int hi, int size, int antialias)
{
FT_Face face;
FT_Error e;
Memimage *m, *mc, *m1;
double pixel_size;
int w, x, y, y0;
int i;
Fontchar *fc, *fc0;
Memsubfont *sf;
//Point rect_points[4];
e = FT_New_Face(lib, xf->fontfile, xf->index, &face);
if(e){
fprint(2, "load failed for %s (%s) index:%d\n", xf->name, xf->fontfile, xf->index);
return nil;
}
e = FT_Set_Char_Size(face, 0, size<<6, dpi, dpi);
if(e){
fprint(2, "FT_Set_Char_Size failed\n");
FT_Done_Face(face);
return nil;
}
pixel_size = (dpi*size)/72.0;
w = x = (int)((face->max_advance_width) * pixel_size/xf->unit + 0.99999999);
y = (int)((face->ascender - face->descender) * pixel_size/xf->unit + 0.99999999);
y0 = (int)(-face->descender * pixel_size/xf->unit + 0.99999999);
m = allocmemimage(Rect(0, 0, x*(hi+1-lo)+1, y+1), antialias ? GREY8 : GREY1);
if(m == nil) {
FT_Done_Face(face);
return nil;
}
mc = allocmemimage(Rect(0, 0, x+1, y+1), antialias ? GREY8 : GREY1);
if(mc == nil) {
freememimage(m);
FT_Done_Face(face);
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);
FT_Done_Face(face);
return nil;
}
fc0 = fc;
//rect_points[0] = mc->r.min;
//rect_points[1] = Pt(mc->r.max.x, mc->r.min.y);
//rect_points[2] = mc->r.max;
//rect_points[3] = Pt(mc->r.min.x, mc->r.max.y);
x = 0;
for(i=lo; i<=hi; i++, fc++) {
int k, r;
int advance;
memfillcolor(mc, DBlack);
fc->x = x;
fc->top = 0;
fc->bottom = Dy(m->r);
e = 1;
k = FT_Get_Char_Index(face, i);
if(k != 0) {
e = FT_Load_Glyph(face, k, FT_LOAD_RENDER|FT_LOAD_NO_HINTING|(antialias ? 0:FT_LOAD_TARGET_MONO));
}
if(e || face->glyph->advance.x <= 0) {
fc->width = 0;
fc->left = 0;
if(i == 0) {
drawpjw(m, fc, x, w, y, y - y0);
x += fc->width;
}
continue;
}
FT_Bitmap *bitmap = &face->glyph->bitmap;
uchar *base = byteaddr(mc, mc->r.min);
advance = (face->glyph->advance.x+32) >> 6;
for(r=0; r < bitmap->rows; r++)
memmove(base + r*mc->width*sizeof(u32int), bitmap->buffer + r*bitmap->pitch, bitmap->pitch);
memimagedraw(m, Rect(x, 0, x + advance, y), mc,
Pt(-face->glyph->bitmap_left, -(y - y0 - face->glyph->bitmap_top)),
memopaque, ZP, S);
fc->width = advance;
fc->left = 0;
x += advance;
#ifdef DEBUG_FT_BITMAP
for(r=0; r < bitmap->rows; r++) {
int c;
uchar *span = bitmap->buffer+(r*bitmap->pitch);
for(c = 0; c < bitmap->width; c++) {
fprint(1, "%02x", span[c]);
}
fprint(1,"\n");
}
#endif
#ifdef DEBUG_9_BITMAP
for(r=0; r < mc->r.max.y; r++) {
int c;
uchar *span = base+(r*mc->width*sizeof(u32int));
for(c = 0; c < Dx(mc->r); c++) {
fprint(1, "%02x", span[c]);
}
fprint(1,"\n");
}
#endif
}
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;
FT_Done_Face(face);
return sf;
}