plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

x11.c (5847B)


      1 #include <u.h>
      2 
      3 #include <fontconfig/fontconfig.h>
      4 #include <ft2build.h>
      5 #include FT_FREETYPE_H
      6 
      7 #include <libc.h>
      8 #include <draw.h>
      9 #include <memdraw.h>
     10 #include "a.h"
     11 
     12 static FcConfig    *fc;
     13 static FT_Library  lib;
     14 static int         dpi = 96;
     15 
     16 void
     17 loadfonts(void)
     18 {
     19 	int i;
     20 	FT_Error e;
     21 	FcFontSet *sysfonts;
     22 
     23 	if(!FcInit() || (fc=FcInitLoadConfigAndFonts()) == NULL) {
     24 		fprint(2, "fontconfig initialization failed\n");
     25 		exits("fontconfig failed");
     26 	}
     27 
     28 	e = FT_Init_FreeType(&lib);
     29 	if(e) {
     30 		fprint(2, "freetype initialization failed: %d\n", e);
     31 		exits("freetype failed");
     32 	}
     33 
     34 	sysfonts = FcConfigGetFonts(fc, FcSetSystem);
     35 
     36 	xfont = emalloc9p(sysfonts->nfont*sizeof xfont[0]);
     37 	memset(xfont, 0, sysfonts->nfont*sizeof xfont[0]);
     38 	for(i=0; i<sysfonts->nfont; i++) {
     39 		FcChar8 *fullname, *fontfile;
     40 		int index;
     41 		FcPattern *pat = sysfonts->fonts[i];
     42 
     43 		if(FcPatternGetString(pat, FC_POSTSCRIPT_NAME, 0, &fullname) != FcResultMatch ||
     44 		   FcPatternGetString(pat, FC_FILE, 0, &fontfile) != FcResultMatch     ||
     45 		   FcPatternGetInteger(pat, FC_INDEX, 0, &index) != FcResultMatch)
     46 			continue;
     47 
     48 		xfont[nxfont].name     = strdup((char*)fullname);
     49 		xfont[nxfont].fontfile = strdup((char*)fontfile);
     50 		xfont[nxfont].index    = index;
     51 		nxfont++;
     52 	}
     53 
     54 	FcFontSetDestroy(sysfonts);
     55 }
     56 
     57 void
     58 load(XFont *f)
     59 {
     60 	FT_Face face;
     61 	FT_Error e;
     62 	FT_ULong charcode;
     63 	FT_UInt glyph_index;
     64 	int i;
     65 
     66 	if(f->loaded)
     67 		return;
     68 
     69 	e = FT_New_Face(lib, f->fontfile, f->index, &face);
     70 	if(e){
     71 		fprint(2, "load failed for %s (%s) index:%d\n", f->name, f->fontfile, f->index);
     72 		return;
     73 	}
     74 	if(!FT_IS_SCALABLE(face)) {
     75 		fprint(2, "%s is a non scalable font, skipping\n", f->name);
     76 		FT_Done_Face(face);
     77 		f->loaded = 1;
     78 		return;
     79 	}
     80 	f->unit = face->units_per_EM;
     81 	f->height = (int)((face->ascender - face->descender) * 1.35);
     82 	f->originy = face->descender * 1.35; // bbox.yMin (or descender)  is negative, because the baseline is y-coord 0
     83 
     84 	for(charcode=FT_Get_First_Char(face, &glyph_index); glyph_index != 0;
     85 		charcode=FT_Get_Next_Char(face, charcode, &glyph_index)) {
     86 
     87 		int idx = charcode/SubfontSize;
     88 
     89 		if(charcode > Runemax)
     90 			break;
     91 
     92 		if(!f->range[idx])
     93 			f->range[idx] = 1;
     94 	}
     95 	FT_Done_Face(face);
     96 
     97 	// libdraw expects U+0000 to be present
     98 	if(!f->range[0])
     99 		f->range[0] = 1;
    100 
    101 	// fix up file list
    102 	for(i=0; i<nelem(f->range); i++)
    103 		if(f->range[i])
    104 			f->file[f->nfile++] = i;
    105 
    106 	f->loaded = 1;
    107 }
    108 
    109 Memsubfont*
    110 mksubfont(XFont *xf, char *name, int lo, int hi, int size, int antialias)
    111 {
    112 	FT_Face face;
    113 	FT_Error e;
    114 	Memimage *m, *mc, *m1;
    115 	double pixel_size;
    116 	int w, x, y, y0;
    117 	int i;
    118 	Fontchar *fc, *fc0;
    119 	Memsubfont *sf;
    120 	//Point rect_points[4];
    121 
    122 	e = FT_New_Face(lib, xf->fontfile, xf->index, &face);
    123 	if(e){
    124 		fprint(2, "load failed for %s (%s) index:%d\n", xf->name, xf->fontfile, xf->index);
    125 		return nil;
    126 	}
    127 
    128 	e = FT_Set_Char_Size(face, 0, size<<6, dpi, dpi);
    129 	if(e){
    130 		fprint(2, "FT_Set_Char_Size failed\n");
    131 		FT_Done_Face(face);
    132 		return nil;
    133 	}
    134 
    135 	pixel_size = (dpi*size)/72.0;
    136 	w = x = (int)((face->max_advance_width) * pixel_size/xf->unit + 0.99999999);
    137 	y = (int)((face->ascender - face->descender) * pixel_size/xf->unit + 0.99999999);
    138 	y0 = (int)(-face->descender * pixel_size/xf->unit + 0.99999999);
    139 
    140 	m = allocmemimage(Rect(0, 0, x*(hi+1-lo)+1, y+1), antialias ? GREY8 : GREY1);
    141 	if(m == nil) {
    142 		FT_Done_Face(face);
    143 		return nil;
    144 	}
    145 	mc = allocmemimage(Rect(0, 0, x+1, y+1), antialias ? GREY8 : GREY1);
    146 	if(mc == nil) {
    147 		freememimage(m);
    148 		FT_Done_Face(face);
    149 		return nil;
    150 	}
    151 	memfillcolor(m, DBlack);
    152 	memfillcolor(mc, DBlack);
    153 	fc = malloc((hi+2 - lo) * sizeof fc[0]);
    154 	sf = malloc(sizeof *sf);
    155 	if(fc == nil || sf == nil) {
    156 		freememimage(m);
    157 		freememimage(mc);
    158 		free(fc);
    159 		free(sf);
    160 		FT_Done_Face(face);
    161 		return nil;
    162 	}
    163 	fc0 = fc;
    164 
    165 	//rect_points[0] = mc->r.min;
    166 	//rect_points[1] = Pt(mc->r.max.x, mc->r.min.y);
    167 	//rect_points[2] = mc->r.max;
    168 	//rect_points[3] = Pt(mc->r.min.x, mc->r.max.y);
    169 
    170 	x = 0;
    171 	for(i=lo; i<=hi; i++, fc++) {
    172 		int k, r;
    173 		int advance;
    174 
    175 		memfillcolor(mc, DBlack);
    176 
    177 		fc->x = x;
    178 		fc->top = 0;
    179 		fc->bottom = Dy(m->r);
    180 		e = 1;
    181 		k = FT_Get_Char_Index(face, i);
    182 		if(k != 0) {
    183 			e = FT_Load_Glyph(face, k, FT_LOAD_RENDER|FT_LOAD_NO_AUTOHINT|(antialias ? 0:FT_LOAD_TARGET_MONO));
    184 		}
    185 		if(e || face->glyph->advance.x <= 0) {
    186 			fc->width = 0;
    187 			fc->left = 0;
    188 			if(i == 0) {
    189 				drawpjw(m, fc, x, w, y, y - y0);
    190 				x += fc->width;
    191 			}
    192 			continue;
    193 		}
    194 
    195 		FT_Bitmap *bitmap = &face->glyph->bitmap;
    196 		uchar *base = byteaddr(mc, mc->r.min);
    197 		advance = (face->glyph->advance.x+32) >> 6;
    198 
    199 		for(r=0; r < bitmap->rows; r++)
    200 			memmove(base + r*mc->width*sizeof(u32int), bitmap->buffer + r*bitmap->pitch, bitmap->pitch);
    201 
    202 		memimagedraw(m, Rect(x, 0, x + advance, y), mc,
    203 			Pt(-face->glyph->bitmap_left, -(y - y0 - face->glyph->bitmap_top)),
    204 			memopaque, ZP, S);
    205 
    206 		fc->width = advance;
    207 		fc->left = 0;
    208 		x += advance;
    209 
    210 #ifdef DEBUG_FT_BITMAP
    211 		for(r=0; r < bitmap->rows; r++) {
    212 			int c;
    213 			uchar *span = bitmap->buffer+(r*bitmap->pitch);
    214 			for(c = 0; c < bitmap->width; c++) {
    215 				fprint(1, "%02x", span[c]);
    216 			}
    217 			fprint(1,"\n");
    218 		}
    219 #endif
    220 
    221 #ifdef DEBUG_9_BITMAP
    222 		for(r=0; r < mc->r.max.y; r++) {
    223 			int c;
    224 			uchar *span = base+(r*mc->width*sizeof(u32int));
    225 			for(c = 0; c < Dx(mc->r); c++) {
    226 				fprint(1, "%02x", span[c]);
    227 			}
    228 			fprint(1,"\n");
    229 		}
    230 #endif
    231 	}
    232 	fc->x = x;
    233 
    234 	// round up to 32-bit boundary
    235 	// so that in-memory data is same
    236 	// layout as in-file data.
    237 	if(x == 0)
    238 		x = 1;
    239 	if(y == 0)
    240 		y = 1;
    241 	if(antialias)
    242 		x += -x & 3;
    243 	else
    244 		x += -x & 31;
    245 	m1 = allocmemimage(Rect(0, 0, x, y), antialias ? GREY8 : GREY1);
    246 	memimagedraw(m1, m1->r, m, m->r.min, memopaque, ZP, S);
    247 	freememimage(m);
    248 	freememimage(mc);
    249 
    250 	sf->name = nil;
    251 	sf->n = hi+1 - lo;
    252 	sf->height = Dy(m1->r);
    253 	sf->ascent = Dy(m1->r) - y0;
    254 	sf->info = fc0;
    255 	sf->bits = m1;
    256 
    257 	FT_Done_Face(face);
    258 	return sf;
    259 }