From 6721f8b1d73d5b60cf94b8d2c0b9a087a2221357 Mon Sep 17 00:00:00 2001 From: Ali Gholami Rudi Date: Fri, 27 Apr 2012 18:59:58 +0430 Subject: [PATCH] fbpad: support multiple fonts The new "m-f x" command changes the fonts used in a terminal where x denotes the fontset. The fonts in each fontset are defined in config.h: FR0, FI0, and FB0 are the regular, italic, and bold font in fontset 0. --- Makefile | 2 +- README | 3 +- config.h | 7 ++- fbpad.c | 21 +++++++-- font.c | 74 +++++++++++++++++--------------- font.h | 10 ++--- pad.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++---------------- pad.h | 4 ++ term.c | 18 +++++--- 9 files changed, 199 insertions(+), 88 deletions(-) diff --git a/Makefile b/Makefile index 875b077..bd19e08 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CFLAGS = -Wall -O2 LDFLAGS = all: fbpad -%.o: %.c +%.o: %.c config.h $(CC) -c $(CFLAGS) $< fbpad: fbpad.o term.o pad.o draw.o font.o scrsnap.o $(CC) -o $@ $^ $(LDFLAGS) diff --git a/README b/README index c16fbae..aefb810 100644 --- a/README +++ b/README @@ -21,13 +21,14 @@ m-tab show next terminal m-s create a text screenshot (SCRSHOT) m-y redraw terminal c-m-q quit fbpad +m-f x use font x in this terminal ============== ======================================= SETTING UP ========== You can edit config.h to configure fbpad. To get fbpad running you need -to make sure TINYFONT points to a valid tinyfont file and SHELL is the +to make sure F* point to a valid tinyfont file and SHELL is the shell you want to execute. Also the type of fbval_t should match the framebuffer depth: unsigned char for 8-bit, short for 16-bit and int for 24/32-bit framebuffers. Once these are set, you should be able to diff --git a/config.h b/config.h index dc64c08..3b226fc 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,12 @@ #define MAIL "mailx" #define EDITOR "vi" -#define TINYFONT "/path/to/tinyfont/file.tf" +/* fontsets; tinyfont files for regular, italic, and bold fonts */ +#define F0 {"/path/to/font.tf", NULL, NULL} +#define F1 {} +#define F2 {} +#define F3 {} +#define F4 {} #define FGCOLOR 0 #define BGCOLOR 7 diff --git a/fbpad.c b/fbpad.c index d54b591..a33b820 100644 --- a/fbpad.c +++ b/fbpad.c @@ -32,9 +32,11 @@ static char tags[] = TAGS; static struct term terms[NTERMS]; -static int tops[NTAGS]; /* top terms of tags */ -static int ctag; /* current tag */ -static int ltag; /* the last tag */ +static int tops[NTAGS]; /* top terms of tags */ +static int ctag; /* current tag */ +static int ltag; /* the last tag */ +static int fonts[NTERMS]; /* term fonts */ +static int setfont; /* the next character is font */ static int exitit; static int hidden; @@ -59,6 +61,8 @@ static void term_switch(int oidx, int nidx, int show, int save, int load) term_save(&terms[oidx]); if (show && load && TERMOPEN(nidx) && TERMSNAP(nidx)) flags = scr_load(&terms[nidx]) ? TERM_REDRAW : TERM_VISIBLE; + if (show) + pad_font(fonts[nidx]); term_load(&terms[nidx], flags); } @@ -138,6 +142,14 @@ static void showtags(void) static void directkey(void) { int c = readchar(); + if (setfont && c != -1) { + setfont = 0; + if (c != ESC && isdigit(c)) { + fonts[cterm()] = c - '0'; + term_switch(cterm(), cterm(), 1, 0, 1); + } + return; + } if (c == ESC) { switch ((c = readchar())) { case 'c': @@ -171,6 +183,9 @@ static void directkey(void) case 'y': term_switch(cterm(), cterm(), 1, 0, 1); return; + case 'f': + setfont = 1; + return; default: if (strchr(tags, c)) { showtag(strchr(tags, c) - tags); diff --git a/font.c b/font.c index c0acadc..6164134 100644 --- a/font.c +++ b/font.c @@ -7,11 +7,13 @@ #include "font.h" #include "util.h" -static int fd; -static int rows; -static int cols; -static int n; -static int *glyphs; +struct font { + int fd; + int rows; + int cols; + int n; + int *glyphs; +}; /* * tinyfont format: @@ -32,33 +34,35 @@ struct tinyfont { int rows, cols; }; -int font_init(void) +struct font *font_open(char *path) { + struct font *font; struct tinyfont head; - fd = open(TINYFONT, O_RDONLY); - if (fd == -1) - return 1; - fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); - if (read(fd, &head, sizeof(head)) != sizeof(head)) - return 1; - n = head.n; - rows = head.rows; - cols = head.cols; - glyphs = malloc(n * sizeof(int)); - if (read(fd, glyphs, n * sizeof(int)) != n * sizeof(int)) - return 1; - return 0; + font = malloc(sizeof(*font)); + font->fd = open(path, O_RDONLY); + if (font->fd == -1) + return NULL; + fcntl(font->fd, F_SETFD, fcntl(font->fd, F_GETFD) | FD_CLOEXEC); + if (read(font->fd, &head, sizeof(head)) != sizeof(head)) + return NULL; + font->n = head.n; + font->rows = head.rows; + font->cols = head.cols; + font->glyphs = malloc(font->n * sizeof(int)); + if (read(font->fd, font->glyphs, font->n * sizeof(int)) != font->n * sizeof(int)) + return NULL; + return font; } -static int find_glyph(int c) +static int find_glyph(struct font *font, int c) { int l = 0; - int h = n; + int h = font->n; while (l < h) { int m = (l + h) / 2; - if (glyphs[m] == c) + if (font->glyphs[m] == c) return m; - if (c < glyphs[m]) + if (c < font->glyphs[m]) h = m; else l = m + 1; @@ -66,28 +70,30 @@ static int find_glyph(int c) return -1; } -int font_bitmap(void *dst, int c) +int font_bitmap(struct font *font, void *dst, int c) { - int i = find_glyph(c); + int i = find_glyph(font, c); if (i < 0) return 1; - lseek(fd, sizeof(struct tinyfont) + n * sizeof(int) + i * rows * cols, 0); - read(fd, dst, rows * cols); + lseek(font->fd, sizeof(struct tinyfont) + font->n * sizeof(int) + + i * font->rows * font->cols, 0); + read(font->fd, dst, font->rows * font->cols); return 0; } -void font_free(void) +void font_free(struct font *font) { - free(glyphs); - close(fd); + free(font->glyphs); + close(font->fd); + free(font); } -int font_rows(void) +int font_rows(struct font *font) { - return rows; + return font->rows; } -int font_cols(void) +int font_cols(struct font *font) { - return cols; + return font->cols; } diff --git a/font.h b/font.h index 1d875c5..c69d5ca 100644 --- a/font.h +++ b/font.h @@ -1,7 +1,7 @@ #define MAXDOTS (1 << 10) -int font_init(void); -void font_free(void); -int font_rows(void); -int font_cols(void); -int font_bitmap(void *dst, int c); +struct font *font_open(char *path); +void font_free(struct font *font); +int font_rows(struct font *font); +int font_cols(struct font *font); +int font_bitmap(struct font *font, void *dst, int c); diff --git a/pad.c b/pad.c index eb022ca..9dc003e 100644 --- a/pad.c +++ b/pad.c @@ -8,33 +8,64 @@ #include "util.h" #include "pad.h" +#define NCACHE (1 << 11) +#define MAXFBWIDTH (1 << 12) + static unsigned int cd[] = { COLOR0, COLOR1, COLOR2, COLOR3, COLOR4, COLOR5, COLOR6, COLOR7, COLOR8, COLOR9, COLOR10, COLOR11, COLOR12, COLOR13, COLOR14, COLOR15}; static int rows, cols; +static int fnrows, fncols; +static struct font *fonts[32]; +static int nfonts; +static int font; + +static int fnsets[16][3]; +static char *fnpaths[][3] = {F0, F1, F2, F3, F4}; + +static int fontadd(char *path) +{ + fonts[nfonts] = font_open(path); + if (!fonts[nfonts]) { + fprintf(stderr, "pad: bad font <%s>\n", path); + return -1; + } + return nfonts++; +} int pad_init(void) { + int i, j; if (fb_init()) return 1; if (sizeof(fbval_t) != FBM_BPP(fb_mode())) { fprintf(stderr, "pad_init: fbval_t doesn't match fb depth\n"); return 1; } - if (font_init()) { - fprintf(stderr, "pad_init: loading font failed\n"); - return 1; + for (i = 0; i < ARRAY_SIZE(fnpaths); i++) { + for (j = 0; j < 3; j++) { + int fn = -1; + if (fnpaths[i][j]) + if ((fn = fontadd(fnpaths[i][j])) < 0) + return 1; + if (fn < 0 && j > 0) + fn = fnsets[i][0]; + if (fn < 0 && i > 0) + fn = fnsets[0][j]; + fnsets[i][j] = fn; + } } - rows = fb_rows() / font_rows(); - cols = fb_cols() / font_cols(); + pad_font(0); return 0; } void pad_free(void) { - font_free(); + int i; + for (i = 0; i < nfonts; i++) + font_free(fonts[i]); fb_free(); } @@ -43,7 +74,7 @@ void pad_free(void) #define CB(a) ((a) & 0x0000ff) #define COLORMERGE(f, b, c) ((b) + (((f) - (b)) * (c) >> 8u)) -static unsigned mixed_color(int fg, int bg, unsigned char val) +static unsigned mixed_color(int fg, int bg, unsigned val) { unsigned int fore = cd[fg], back = cd[bg]; unsigned char r = COLORMERGE(CR(fore), CR(back), val); @@ -57,42 +88,64 @@ static unsigned color2fb(int c) return FB_VAL(CR(cd[c]), CG(cd[c]), CB(cd[c])); } -#define NCACHE (1 << 11) -static fbval_t cache[NCACHE * MAXDOTS]; +static fbval_t cache[NCACHE][MAXDOTS]; static struct glyph { int c; + int fn; short fg, bg; -} cacheid[NCACHE]; +} glyphs[NCACHE]; + +static struct glyph *glyph_entry(int c, int fn, int fg, int bg) +{ + return &glyphs[(c ^ (fg << 7) ^ (bg << 6) ^ (fn << 8)) & (NCACHE - 1)]; +} + +static fbval_t *glyph_cache(int c, int fn, short fg, short bg) +{ + struct glyph *g = glyph_entry(c, fn, fg, bg); + if (g->c == c && g->fn == fn && g->fg == fg && g->bg == bg) + return cache[g - glyphs]; + return NULL; +} + +static fbval_t *glyph_add(int c, int fn, short fg, short bg) +{ + struct glyph *g = glyph_entry(c, fn, fg, bg); + g->c = c; + g->fg = fg; + g->bg = bg; + g->fn = fn; + return cache[g - glyphs]; +} -static int glyph_hash(int c, int fg, int bg) +static void bmp2fb(fbval_t *d, char *s, int fg, int bg, int nr, int nc) { - return (c ^ (fg << 7) ^ (bg << 6)) & (NCACHE - 1); + int i, j; + for (i = 0; i < fnrows; i++) { + for (j = 0; j < fncols; j++) { + unsigned v = i < nr && j < nc ? + (unsigned char) s[i * nc + j] : 0; + d[i * fncols + j] = mixed_color(fg, bg, v); + } + } } -static fbval_t *bitmap(int c, short fg, short bg) +static fbval_t *ch2fb(int fn, int c, short fg, short bg) { - unsigned char bits[MAXDOTS]; + char bits[MAXDOTS]; fbval_t *fbbits; - struct glyph *glyph; - int i; - int nbits = font_rows() * font_cols(); if (c < 0 || (c < 256 && (!isprint(c) || isspace(c)))) return NULL; - glyph = &cacheid[glyph_hash(c, fg, bg)]; - fbbits = &cache[glyph_hash(c, fg, bg) * MAXDOTS]; - if (glyph->c == c && glyph->fg == fg && glyph->bg == bg) + if ((fbbits = glyph_cache(c, fn, fg, bg))) return fbbits; - if (font_bitmap(bits, c)) + if (font_bitmap(fonts[fn], bits, c)) return NULL; - glyph->c = c; - glyph->fg = fg; - glyph->bg = bg; - for (i = 0; i < nbits; i++) - fbbits[i] = mixed_color(fg, bg, bits[i]); + fbbits = glyph_add(c, fn, fg, bg); + bmp2fb(fbbits, bits, FN_C(fg), FN_C(bg), + font_rows(fonts[fn]), font_cols(fonts[fn])); return fbbits; } -#define MAXFBWIDTH (1 << 12) static void fb_box(int sr, int sc, int er, int ec, fbval_t val) { static fbval_t line[MAXFBWIDTH]; @@ -104,30 +157,40 @@ static void fb_box(int sr, int sc, int er, int ec, fbval_t val) fb_set(i, sc, line, cn); } +static int fnsel(int fg, int bg) +{ + if ((fg | bg) & FN_B) + return fnsets[font][2]; + if ((fg | bg) & FN_I) + return fnsets[font][1]; + return fnsets[font][0]; +} + void pad_put(int ch, int r, int c, int fg, int bg) { - int sr = font_rows() * r; - int sc = font_cols() * c; - int frows = font_rows(), fcols = font_cols(); + int sr = fnrows * r; + int sc = fncols * c; int i; - fbval_t *bits = bitmap(ch, fg, bg); + fbval_t *bits = ch2fb(fnsel(fg, bg), ch, fg, bg); + if (!bits) + bits = ch2fb(0, ch, fg, bg); if (!bits) - fb_box(sr, sc, sr + frows, sc + fcols, color2fb(bg)); + fb_box(sr, sc, sr + fnrows, sc + fncols, color2fb(FN_C(bg))); else - for (i = 0; i < frows; i++) - fb_set(sr + i, sc, bits + (i * fcols), fcols); + for (i = 0; i < fnrows; i++) + fb_set(sr + i, sc, bits + (i * fncols), fncols); } void pad_blank(int c) { - fb_box(0, 0, fb_rows(), fb_cols(), color2fb(c)); + fb_box(0, 0, fb_rows(), fb_cols(), color2fb(FN_C(c))); } void pad_blankrow(int r, int bg) { - int sr = r * font_rows(); - int er = r == rows - 1 ? fb_rows() : (r + 1) * font_rows(); - fb_box(sr, 0, er, fb_cols(), color2fb(bg)); + int sr = r * fnrows; + int er = r == rows - 1 ? fb_rows() : (r + 1) * fnrows; + fb_box(sr, 0, er, fb_cols(), color2fb(FN_C(bg))); } int pad_rows(void) @@ -139,3 +202,12 @@ int pad_cols(void) { return cols; } + +void pad_font(int i) +{ + font = i < ARRAY_SIZE(fnpaths) ? i : 0; + fnrows = font_rows(fonts[fnsets[0][0]]); + fncols = font_cols(fonts[fnsets[0][0]]); + rows = fb_rows() / fnrows; + cols = fb_cols() / fncols; +} diff --git a/pad.h b/pad.h index 9b3d960..814b6d0 100644 --- a/pad.h +++ b/pad.h @@ -1,4 +1,7 @@ #define MAXCHARS (1 << 15) +#define FN_I 0x10 +#define FN_B 0x20 +#define FN_C(fg) (((fg) & FN_B ? (fg) + 8 : (fg)) & 0x0f) int pad_init(void); void pad_free(void); @@ -7,3 +10,4 @@ int pad_rows(void); int pad_cols(void); void pad_blank(int c); void pad_blankrow(int r, int bg); +void pad_font(int n); diff --git a/term.c b/term.c index 66415f1..5e5e9dd 100644 --- a/term.c +++ b/term.c @@ -20,10 +20,11 @@ #define MODE_AUTOCR 0x08 #define MODE_DEFAULT (MODE_CURSOR | MODE_WRAP) #define ATTR_BOLD 0x10 -#define ATTR_REV 0x20 -#define ATTR_ALL (ATTR_BOLD | ATTR_REV) -#define MODE_INSERT 0x40 -#define MODE_WRAPREADY 0x80 +#define ATTR_ITALIC 0x20 +#define ATTR_REV 0x40 +#define ATTR_ALL (ATTR_BOLD | ATTR_ITALIC | ATTR_REV) +#define MODE_INSERT 0x100 +#define MODE_WRAPREADY 0x200 #define BIT_SET(i, b, val) ((val) ? ((i) | (b)) : ((i) & ~(b))) #define OFFSET(r, c) ((r) * pad_cols() + (c)) @@ -46,7 +47,11 @@ static int lazy; static char fgcolor(void) { int c = mode & ATTR_REV ? bg : fg; - return mode & ATTR_BOLD ? c | 0x08 : c; + if (mode & ATTR_BOLD) + c |= FN_B; + if (mode & ATTR_ITALIC) + c |= FN_I; + return c; } static char bgcolor(void) @@ -491,6 +496,9 @@ static void setattr(int m) case 1: mode |= ATTR_BOLD; break; + case 3: + mode |= ATTR_ITALIC; + break; case 7: mode |= ATTR_REV; break; -- 2.11.4.GIT