Blob


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