commit 9c611279288ca016aeb214da4a23a8e2cce45027 from: Yuval Pavel Zholkover via: Russ Cox date: Sun Oct 21 20:49:13 2012 UTC fontsrv: x11 support R=rsc, 0intro CC=plan9port.codebot http://codereview.appspot.com/6739047 commit - e13727e3c4921bde411c275aef71999324cd3faf commit + 9c611279288ca016aeb214da4a23a8e2cce45027 blob - 59b06cc8b9d74fc39f2fd705b25e81de9bfd112f blob + e1ea4fb5ad53f9e61001a01190f858aa7e9d9806 --- CONTRIBUTORS +++ CONTRIBUTORS @@ -32,6 +32,7 @@ Mathieu Lonjaret Michael Teichgräber Michael Teichgräber Nikolai Saoukh +Yuval Pavel Zholkover Peter Saveliev Richard Miller Rob Kroeger blob - 0781fbab5abee3b54560adbb86bc3d1d11374010 blob + 9f132e92a7597691f46d6be706661ced0d06d501 --- src/cmd/fontsrv/a.h +++ src/cmd/fontsrv/a.h @@ -11,6 +11,10 @@ struct XFont int unit; double height; double originy; + + // fontconfig workarround, as FC_FULLNAME does not work for matching fonts. + char *fontfile; + int index; }; void loadfonts(void); blob - /dev/null blob + ca7a02618255911f7961853a39555730d102ed78 (mode 644) --- /dev/null +++ src/cmd/fontsrv/freetyperules.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ "x$1" = "xx11" ]; then + echo 'CFLAGS=$CFLAGS -I/usr/include/freetype2' + echo 'LDFLAGS=$LDFLAGS -lfontconfig -lfreetype -lz' +fi + blob - 3d23062e94139cfdc8e9857ad7c577aa3b3361fe blob + fb3d86b20c2293f98953adc5ea6631e20d00d1a6 --- src/cmd/fontsrv/mkfile +++ src/cmd/fontsrv/mkfile @@ -1,5 +1,6 @@ -<|sh ../devdraw/mkwsysrules.sh <$PLAN9/src/mkhdr +<|sh ../devdraw/mkwsysrules.sh +<|sh freetyperules.sh $WSYSTYPE TARG=fontsrv blob - f1fb3cd930612e6761f49b72f6b2ec754670c2ff blob + 01f2b9654753a4e94b55a9dfa38e34c8c82aa065 --- src/cmd/fontsrv/x11.c +++ src/cmd/fontsrv/x11.c @@ -1,2 +1,261 @@ -/* maybe someday */ -#include "nowsys.c" +#include + +#include +#include +#include FT_FREETYPE_H + +#include +#include +#include +#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; infont; i++) { + FcChar8 *fullname, *fontfile; + int index; + FcPattern *pat = sysfonts->fonts[i]; + + if(FcPatternGetString(pat, FC_FULLNAME, 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>>8; + + if(charcode > 0xffff) + break; + + if(!f->range[idx]) { + f->range[idx] = 1; + f->nrange++; + } + } + + FT_Done_Face(face); + f->loaded = 1; +} + +Memsubfont* +mksubfont(char *name, int lo, int hi, int size, int antialias) +{ + XFont *xf, *xfp, *xfe; + FT_Face face; + FT_Error e; + Memimage *m, *mc, *m1; + double pixel_size; + int x, y, y0; + int i; + Fontchar *fc, *fc0; + 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){ + 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; + 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), y), antialias ? GREY8 : GREY1); + if(m == nil) { + FT_Done_Face(face); + return nil; + } + mc = allocmemimage(Rect(0, 0, x, y), 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 r; + int advance; + + memfillcolor(mc, DBlack); + + e = FT_Load_Char(face, i, FT_LOAD_RENDER|(antialias ? 0:FT_LOAD_TARGET_MONO)); + if(e){ + fprint(2, "FT_Load_Char failed for %d\n", i); + //mempoly(mc, rect_points, 4, Endsquare, Endsquare, 0, memopaque, ZP, S); + memimageline(mc, m->r.min, Pt(m->r.max.x, m->r.min.y), Endsquare, Endsquare, 0, memopaque, ZP, S); + memimageline(mc, m->r.min, Pt(m->r.min.x, m->r.max.y), Endsquare, Endsquare, 0, memopaque, ZP, S); + memimageline(mc, Pt(m->r.max.x, m->r.min.y), m->r.max, Endsquare, Endsquare, 0, memopaque, ZP, S); + memimageline(mc, Pt(m->r.min.x, m->r.max.y), m->r.max, Endsquare, Endsquare, 0, memopaque, ZP, S); + memimageline(mc, m->r.min, m->r.max, Endsquare, Endsquare, 0, memopaque, ZP, S); + advance = Dx(m->r); + + memimagedraw(m, Rect(x, 0, x + advance, y), mc, ZP, memopaque, ZP, S); + } else { + 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->x = x; + fc->top = 0; + fc->bottom = y; + fc->left = 0; + fc->width = advance; + 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(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; + + FT_Done_Face(face); + return sf; +}