#include "dat.h" #include #include FT_FREETYPE_H #include "fn.h" typedef struct Font Font; struct Font { FT_Face face; int base; }; static FT_Library lib; static Font fonts[Maxfonts]; static int nfonts; static u32int blendtab[2][256]; static u32int blend(u32int bg, u32int fg, int a) { int r, g, b, inv; inv = 255 - a; r = ((bg >> 16 & 0xff) * inv + (fg >> 16 & 0xff) * a) / 255; g = ((bg >> 8 & 0xff) * inv + (fg >> 8 & 0xff) * a) / 255; b = ((bg & 0xff) * inv + (fg & 0xff) * a) / 255; return (r << 16) | (g << 8) | b; } static int loadfont(char *path) { FT_Face face; Font *f; vlong height, pixels; if(nfonts >= nelem(fonts)) return 0; if(FT_New_Face(lib, path, 0, &face) != 0){ fprint(2, "strans: popup: can't load font: %s\n", path); return 0; } height = (vlong)face->ascender - face->descender; if(height <= 0 || face->units_per_EM == 0){ fprint(2, "strans: popup: invalid font metrics: %s\n", path); FT_Done_Face(face); return 0; } pixels = (vlong)Fontsz * face->units_per_EM / height; if(pixels < 1) pixels = 1; if(FT_Set_Pixel_Sizes(face, 0, pixels) != 0){ fprint(2, "strans: popup: can't size font: %s\n", path); FT_Done_Face(face); return 0; } f = &fonts[nfonts]; f->face = face; f->base = (vlong)Fontsz * face->ascender / height; nfonts++; return 1; } static void clearfonts(void) { int i; for(i = 0; i < nfonts; i++){ FT_Done_Face(fonts[i].face); fonts[i].face = nil; } nfonts = 0; } int fontinit(char **path, int npath) { int i, a; if(path == nil || npath < 1 || npath > nelem(fonts)){ fprint(2, "strans: popup: need 1-%d font files\n", nelem(fonts)); clearfonts(); return 0; } if(lib == nil && FT_Init_FreeType(&lib) != 0){ fprint(2, "strans: popup: can't initialize FreeType\n"); return 0; } clearfonts(); for(i = 0; i < npath; i++){ if(path[i] == nil || !loadfont(path[i])){ clearfonts(); return 0; } } for(a = 0; a < 256; a++){ blendtab[0][a] = blend(Colbg, Colfg, a); blendtab[1][a] = blend(Colsel, Colfg, a); } return 1; } static int drawglyph(Font *f, u32int *buf, int w, int h, int px, int py) { FT_Bitmap *b; FT_GlyphSlot g; uchar *row; vlong pitch, x0, x1, y0, y1; int a, sel, x, xa, xb, y, ya, yb; u32int *p; g = f->face->glyph; b = &g->bitmap; if(b->pixel_mode != FT_PIXEL_MODE_GRAY || b->num_grays != 256) return 0; if(b->width == 0 || b->rows == 0) return 1; pitch = b->pitch; if(pitch < 0) pitch = -pitch; if(b->buffer == nil || pitch < b->width) return 0; x0 = (vlong)px + g->bitmap_left; y0 = (vlong)py + f->base - g->bitmap_top; x1 = x0 + b->width; y1 = y0 + b->rows; if(x1 <= 0 || y1 <= 0 || x0 >= w || y0 >= h) return 1; xa = x0 < 0 ? 0 : x0; xb = x1 > w ? w : x1; ya = y0 < 0 ? 0 : y0; yb = y1 > h ? h : y1; for(y = ya; y < yb; y++){ if(b->pitch < 0) row = b->buffer + ((vlong)b->rows - 1 - (y - y0)) * pitch; else row = b->buffer + ((vlong)y - y0) * pitch; for(x = xa; x < xb; x++){ a = row[(vlong)x - x0]; if(a != 0){ p = &buf[y * w + x]; sel = *p == Colsel; *p = blendtab[sel][a]; } } } return 1; } void putfont(u32int *buf, int w, int h, int px, int py, Rune r) { FT_UInt g; int f; if(buf == nil || w <= 0 || h <= 0) return; for(f = 0; f < nfonts; f++){ g = FT_Get_Char_Index(fonts[f].face, r); if(g == 0 || FT_Load_Glyph(fonts[f].face, g, FT_LOAD_DEFAULT) != 0 || FT_Render_Glyph(fonts[f].face->glyph, FT_RENDER_MODE_NORMAL) != 0) continue; if(drawglyph(&fonts[f], buf, w, h, px, py)) return; } }