URI: 
       tfontsrv: x11 support - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 9c611279288ca016aeb214da4a23a8e2cce45027
   DIR parent e13727e3c4921bde411c275aef71999324cd3faf
  HTML Author: Yuval Pavel Zholkover <paulzhol@gmail.com>
       Date:   Sun, 21 Oct 2012 16:49:13 -0400
       
       fontsrv: x11 support
       
       R=rsc, 0intro
       CC=plan9port.codebot
       http://codereview.appspot.com/6739047
       
       Diffstat:
         M CONTRIBUTORS                        |       1 +
         M src/cmd/fontsrv/a.h                 |       4 ++++
         A src/cmd/fontsrv/freetyperules.sh    |       7 +++++++
         M src/cmd/fontsrv/mkfile              |       3 ++-
         M src/cmd/fontsrv/x11.c               |     263 ++++++++++++++++++++++++++++++-
       
       5 files changed, 275 insertions(+), 3 deletions(-)
       ---
   DIR diff --git a/CONTRIBUTORS b/CONTRIBUTORS
       t@@ -32,6 +32,7 @@ Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
        Michael Teichgräber <mt4swm@googlemail.com>
        Michael Teichgräber <mt@ib.wmipf.de>
        Nikolai Saoukh <nikolai.saoukh@gmail.com>
       +Yuval Pavel Zholkover <paulzhol@gmail.com>
        Peter Saveliev <svinota.saveliev@gmail.com>
        Richard Miller <millerresearch@gmail.com>
        Rob Kroeger <robkroeger@gmail.com>
   DIR diff --git a/src/cmd/fontsrv/a.h b/src/cmd/fontsrv/a.h
       t@@ -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);
   DIR diff --git a/src/cmd/fontsrv/freetyperules.sh b/src/cmd/fontsrv/freetyperules.sh
       t@@ -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
       +
   DIR diff --git a/src/cmd/fontsrv/mkfile b/src/cmd/fontsrv/mkfile
       t@@ -1,5 +1,6 @@
       -<|sh ../devdraw/mkwsysrules.sh
        <$PLAN9/src/mkhdr
       +<|sh ../devdraw/mkwsysrules.sh
       +<|sh freetyperules.sh $WSYSTYPE
        
        TARG=fontsrv
        
   DIR diff --git a/src/cmd/fontsrv/x11.c b/src/cmd/fontsrv/x11.c
       t@@ -1,2 +1,261 @@
       -/* maybe someday */
       -#include "nowsys.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_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;
       +}