aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuval Pavel Zholkover <paulzhol@gmail.com>2012-10-21 16:49:13 -0400
committerRuss Cox <rsc@swtch.com>2012-10-21 16:49:13 -0400
commit9c611279288ca016aeb214da4a23a8e2cce45027 (patch)
tree3264b8b1e9bd43f580850b0ba3616879862101b4
parente13727e3c4921bde411c275aef71999324cd3faf (diff)
downloadplan9port-9c611279288ca016aeb214da4a23a8e2cce45027.tar.gz
plan9port-9c611279288ca016aeb214da4a23a8e2cce45027.tar.bz2
plan9port-9c611279288ca016aeb214da4a23a8e2cce45027.zip
fontsrv: x11 support
R=rsc, 0intro CC=plan9port.codebot http://codereview.appspot.com/6739047
-rw-r--r--CONTRIBUTORS1
-rw-r--r--src/cmd/fontsrv/a.h4
-rw-r--r--src/cmd/fontsrv/freetyperules.sh7
-rw-r--r--src/cmd/fontsrv/mkfile3
-rw-r--r--src/cmd/fontsrv/x11.c263
5 files changed, 275 insertions, 3 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 59b06cc8..e1ea4fb5 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -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>
diff --git a/src/cmd/fontsrv/a.h b/src/cmd/fontsrv/a.h
index 0781fbab..9f132e92 100644
--- a/src/cmd/fontsrv/a.h
+++ b/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);
diff --git a/src/cmd/fontsrv/freetyperules.sh b/src/cmd/fontsrv/freetyperules.sh
new file mode 100644
index 00000000..ca7a0261
--- /dev/null
+++ b/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
+
diff --git a/src/cmd/fontsrv/mkfile b/src/cmd/fontsrv/mkfile
index 3d23062e..fb3d86b2 100644
--- a/src/cmd/fontsrv/mkfile
+++ b/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
diff --git a/src/cmd/fontsrv/x11.c b/src/cmd/fontsrv/x11.c
index f1fb3cd9..01f2b965 100644
--- a/src/cmd/fontsrv/x11.c
+++ b/src/cmd/fontsrv/x11.c
@@ -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;
+}