diff options
author | kraxel <kraxel> | 2004-06-07 19:19:20 +0000 |
---|---|---|
committer | kraxel <kraxel> | 2004-06-07 19:19:20 +0000 |
commit | 7c0a76f027d5820af7f2bbbe6abb3234383a5d9b (patch) | |
tree | 8221d4c482d5518c0de163350fc7fe59ea76d033 | |
parent | ec23de55331d3597e625ab42f7b50394ae34be1f (diff) | |
download | fbida-7c0a76f027d5820af7f2bbbe6abb3234383a5d9b.tar.gz |
- fbi: switch over text rendering to freetype2 + fontconfig.
-rw-r--r-- | GNUmakefile | 7 | ||||
-rw-r--r-- | fb-gui.c | 615 | ||||
-rw-r--r-- | fb-gui.h | 32 | ||||
-rw-r--r-- | fbi.c | 452 | ||||
-rw-r--r-- | fs.c | 502 | ||||
-rw-r--r-- | fs.h | 72 |
6 files changed, 718 insertions, 962 deletions
diff --git a/GNUmakefile b/GNUmakefile index 471bd23..b056a25 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -106,7 +106,6 @@ fbi : LDLIBS += $(call ac_lib_mkvar,$(fbi_libs),LDLIBS) # jpeg/exif libs exiftran : LDLIBS += -ljpeg -lexif -lm -genthumbnail : LDLIBS += -ljpeg -lexif -lm thumbnail.cgi : LDLIBS += -lexif -lm exiftran: exiftran.o genthumbnail.o jpegtools.o jpeg/transupp.o \ @@ -156,7 +155,7 @@ ida.o: Ida.ad.h logo.h # object files OBJS_FBI := \ - fbi.o fbtools.o fs.o fb-gui.o desktop.o \ + fbi.o fbtools.o fb-gui.o desktop.o \ parseconfig.o fbiconfig.o \ jpegtools.o jpeg/transupp.o \ dither.o filter.o op.o @@ -164,8 +163,9 @@ OBJS_FBI := \ OBJS_FBI += $(filter-out wr/%,$(call ac_lib_mkvar,$(fbi_libs),OBJS)) # jpeg/exif libs +fbi : CFLAGS += $(shell pkg-config --cflags freetype2 fontconfig) +fbi : LDLIBS += $(shell pkg-config --libs freetype2 fontconfig) fbi : LDLIBS += -ljpeg -lexif -lm -fs.o fb-gui.o : CFLAGS += -DX_DISPLAY_MISSING=1 fbi: $(OBJS_FBI) $(OBJS_READER) @@ -213,4 +213,3 @@ include $(srcdir)/mk/Maintainer.mk sync:: cp $(srcdir)/../xawtv/common/parseconfig.[ch] $(srcdir) cp $(srcdir)/../xawtv/console/fbtools.[ch] $(srcdir) - cp $(srcdir)/../xawtv/console/fs.[ch] $(srcdir) @@ -1,73 +1,277 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <math.h> +#include <wchar.h> +#include <sys/ioctl.h> #include <linux/fb.h> +#include <fontconfig/fontconfig.h> +#include <fontconfig/fcfreetype.h> + #include "fbtools.h" -#include "fs.h" +#include "dither.h" #include "fb-gui.h" /* public */ int visible = 1; -/* private */ -static struct fs_font *f; -static char *x11_font = "10x20"; - static int ys = 3; static int xs = 10; /* ---------------------------------------------------------------------- */ -/* clear screen (areas) */ +/* shadow framebuffer -- internals */ -void fb_clear_mem(void) +static float p_gamma = 1; +static unsigned short p_red[256], p_green[256], p_blue[256]; +static struct fb_cmap p_cmap = { 0, 256, p_red, p_green, p_blue }; + +static int32_t s_lut_red[256], s_lut_green[256], s_lut_blue[256]; + +static unsigned char **shadow; +static unsigned int *sdirty,swidth,sheight; + +static unsigned short calc_gamma(int n, int max) { - if (visible) - fb_memset(fb_mem,0,fb_fix.smem_len); + int ret = 65535.0 * pow((float)n/(max), 1 / p_gamma); + if (ret > 65535) ret = 65535; + if (ret < 0) ret = 0; + return ret; } -void fb_clear_screen(void) +static void +linear_palette(int bit) { - if (visible) - fb_memset(fb_mem,0,fb_fix.line_length * fb_var.yres); + int i, size = 256 >> (8 - bit); + + for (i = 0; i < size; i++) + p_red[i] = p_green[i] = p_blue[i] = calc_gamma(i,size); } -static void fb_clear_rect(int x1, int x2, int y1,int y2) +static void +dither_palette(int r, int g, int b) { - unsigned char *ptr; - int y,h; + int rs, gs, bs, i; + + rs = 256 / (r - 1); + gs = 256 / (g - 1); + bs = 256 / (b - 1); + for (i = 0; i < 256; i++) { + p_red[i] = calc_gamma(rs * ((i / (g * b)) % r), 255); + p_green[i] = calc_gamma(gs * ((i / b) % g), 255); + p_blue[i] = calc_gamma(bs * ((i) % b), 255); + } +} + +static void shadow_lut_init_one(int32_t *lut, int bits, int shift) +{ + int i; + + if (bits > 8) + for (i = 0; i < 256; i++) + lut[i] = (i << (bits + shift - 8)); + else + for (i = 0; i < 256; i++) + lut[i] = (i >> (8 - bits)) << shift; +} + +static void shadow_lut_init(int depth) +{ + if (fb_var.red.length && + fb_var.green.length && + fb_var.blue.length) { + /* fb_var.{red|green|blue} looks sane, use it */ + shadow_lut_init_one(s_lut_red, fb_var.red.length, fb_var.red.offset); + shadow_lut_init_one(s_lut_green, fb_var.green.length, fb_var.green.offset); + shadow_lut_init_one(s_lut_blue, fb_var.blue.length, fb_var.blue.offset); + } else { + /* fallback */ + int i; + switch (depth) { + case 15: + for (i = 0; i < 256; i++) { + s_lut_red[i] = (i & 0xf8) << 7; /* bits -rrrrr-- -------- */ + s_lut_green[i] = (i & 0xf8) << 2; /* bits ------gg ggg----- */ + s_lut_blue[i] = (i & 0xf8) >> 3; /* bits -------- ---bbbbb */ + } + break; + case 16: + for (i = 0; i < 256; i++) { + s_lut_red[i] = (i & 0xf8) << 8; /* bits rrrrr--- -------- */ + s_lut_green[i] = (i & 0xfc) << 3; /* bits -----ggg ggg----- */ + s_lut_blue[i] = (i & 0xf8) >> 3; /* bits -------- ---bbbbb */ + } + break; + case 24: + for (i = 0; i < 256; i++) { + s_lut_red[i] = i << 16; /* byte -r-- */ + s_lut_green[i] = i << 8; /* byte --g- */ + s_lut_blue[i] = i; /* byte ---b */ + } + break; + } + } +} + +static void shadow_render_line(int line, unsigned char *dest, char unsigned *buffer) +{ + unsigned char *ptr = (void*)dest; + unsigned short *ptr2 = (void*)dest; + unsigned long *ptr4 = (void*)dest; + int x; + + switch (fb_var.bits_per_pixel) { + case 8: + dither_line(buffer, ptr, line, swidth); + break; + case 15: + case 16: + for (x = 0; x < swidth; x++) { + ptr2[x] = s_lut_red[buffer[x*3]] | + s_lut_green[buffer[x*3+1]] | + s_lut_blue[buffer[x*3+2]]; + } + break; + case 24: + for (x = 0; x < swidth; x++) { + ptr[3*x+2] = buffer[3*x+0]; + ptr[3*x+1] = buffer[3*x+1]; + ptr[3*x+0] = buffer[3*x+2]; + } + break; + case 32: + for (x = 0; x < swidth; x++) { + ptr4[x] = s_lut_red[buffer[x*3]] | + s_lut_green[buffer[x*3+1]] | + s_lut_blue[buffer[x*3+2]]; + } + break; + } +} + +/* ---------------------------------------------------------------------- */ +/* shadow framebuffer -- management interface */ + +void shadow_render(void) +{ + unsigned int offset = 0; + int i; if (!visible) return; + for (i = 0; i < sheight; i++, offset += fb_fix.line_length) { + if (0 == sdirty[i]) + continue; + shadow_render_line(i, fb_mem + offset, shadow[i]); + sdirty[i] = 0; + } +} + +void shadow_clear_lines(int first, int last) +{ + int i; + + for (i = first; i <= last; i++) { + memset(shadow[i],0,3*swidth); + sdirty[i]++; + } +} + +void shadow_clear(void) +{ + shadow_clear_lines(0, sheight-1); +} + +void shadow_set_palette(int fd) +{ + if (fb_fix.visual != FB_VISUAL_DIRECTCOLOR && fb_var.bits_per_pixel != 8) + return; + if (-1 == ioctl(fd,FBIOPUTCMAP,&p_cmap)) { + perror("ioctl FBIOPUTCMAP"); + exit(1); + } +} - if (x2 < x1) - h = x2, x2 = x1, x1 = h; - if (y2 < y1) - h = y2, y2 = y1, y1 = h; - ptr = fb_mem; - ptr += y1 * fb_fix.line_length; - ptr += x1 * fs_bpp; +void shadow_init(void) +{ + int i; - for (y = y1; y <= y2; y++) { - fb_memset(ptr, 0, (x2 - x1 + 1) * fs_bpp); - ptr += fb_fix.line_length; + /* init shadow fb */ + swidth = fb_var.xres; + sheight = fb_var.yres; + shadow = malloc(sizeof(unsigned char*) * sheight); + sdirty = malloc(sizeof(unsigned int) * sheight); + for (i = 0; i < sheight; i++) + shadow[i] = malloc(swidth*3); + shadow_clear(); + + /* init rendering */ + switch (fb_var.bits_per_pixel) { + case 8: + dither_palette(8, 8, 4); + init_dither(8, 8, 4, 2); + dither_line = dither_line_color; + break; + case 15: + case 16: + if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR) + linear_palette(5); + if (fb_var.green.length == 5) { + shadow_lut_init(15); + } else { + shadow_lut_init(16); + } + break; + case 24: + if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR) + linear_palette(8); + break; + case 32: + if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR) + linear_palette(8); + shadow_lut_init(24); + break; + default: + fprintf(stderr, "Oops: %i bit/pixel ???\n", + fb_var.bits_per_pixel); + exit(1); } } +void shadow_fini(void) +{ + int i; + + if (!shadow) + return; + for (i = 0; i < sheight; i++) + free(shadow[i]); + free(shadow); + free(sdirty); +} + /* ---------------------------------------------------------------------- */ -/* draw lines */ +/* shadow framebuffer -- drawing interface */ -static void fb_setpixel(int x, int y, unsigned int color) +static void shadow_setpixel(int x, int y) { - unsigned char *ptr; + unsigned char *dest = shadow[y] + 3*x; - ptr = fb_mem; - ptr += y * fb_fix.line_length; - ptr += x * fs_bpp; - fs_setpixel(ptr, color); + if (x < 0) + return; + if (x >= swidth) + return; + if (y < 0) + return; + if (y >= sheight) + return; + *(dest++) = 255; + *(dest++) = 255; + *(dest++) = 255; + sdirty[y]++; } -static void fb_line(int x1, int x2, int y1,int y2) +void shadow_draw_line(int x1, int x2, int y1,int y2) { int x,y,h; float inc; @@ -81,84 +285,237 @@ static void fb_line(int x1, int x2, int y1,int y2) inc = (float)(x2-x1)/(float)(y2-y1); for (y = y1; y <= y2; y++) { x = x1 + inc * (y - y1); - fb_setpixel(x,y,fs_white); + shadow_setpixel(x,y); } } else { inc = (float)(y2-y1)/(float)(x2-x1); for (x = x1; x <= x2; x++) { y = y1 + inc * (x - x1); - fb_setpixel(x,y,fs_white); + shadow_setpixel(x,y); } } } -static void fb_rect(int x1, int x2, int y1,int y2) +void shadow_draw_rect(int x1, int x2, int y1,int y2) { - fb_line(x1, x2, y1, y1); - fb_line(x1, x2, y2, y2); - fb_line(x1, x1, y1, y2); - fb_line(x2, x2, y1, y2); + shadow_draw_line(x1, x2, y1, y1); + shadow_draw_line(x1, x2, y2, y2); + shadow_draw_line(x1, x1, y1, y2); + shadow_draw_line(x2, x2, y1, y2); +} + +void shadow_draw_rgbdata(int x, int y, int pixels, unsigned char *rgb) +{ + unsigned char *dest = shadow[y] + 3*x; + + memcpy(dest,rgb,3*pixels); + sdirty[y]++; } -/* ---------------------------------------------------------------------- */ -/* text stuff */ -void fb_text_init1(char *font) +void shadow_darkify(int x1, int x2, int y1,int y2, int percent) { - char *fonts[2] = { font, NULL }; + unsigned char *ptr; + int x,y,h; - if (NULL == f) - f = fs_consolefont(font ? fonts : NULL); -#ifndef X_DISPLAY_MISSING - if (NULL == f && 0 == fs_connect(NULL)) - f = fs_open(font ? font : x11_font); -#endif - if (NULL == f) { - fprintf(stderr,"no font available\n"); - exit(1); + if (x2 < x1) + h = x2, x2 = x1, x1 = h; + if (y2 < y1) + h = y2, y2 = y1, y1 = h; + + for (y = y1; y <= y2; y++) { + if (y < 0) + continue; + if (y >= sheight) + continue; + sdirty[y]++; + ptr = shadow[y]; + for (x = x1; x <= x2; x++) { + if (x < 0) + continue; + if (x >= swidth) + continue; + ptr[3*x+0] = ptr[3*x+0] * percent / 100; + ptr[3*x+1] = ptr[3*x+1] * percent / 100; + ptr[3*x+2] = ptr[3*x+2] * percent / 100; + } } } -void fb_text_init2(void) +void shadow_reverse(int x1, int x2, int y1,int y2) { - fs_init_fb(255); + unsigned char *ptr; + int x,y,h; + + if (x2 < x1) + h = x2, x2 = x1, x1 = h; + if (y2 < y1) + h = y2, y2 = y1, y1 = h; + + for (y = y1; y <= y2; y++) { + if (y < 0) + continue; + if (y >= sheight) + continue; + sdirty[y]++; + ptr = shadow[y]; + for (x = x1; x <= x2; x++) { + if (x < 0) + continue; + if (x >= swidth) + continue; + ptr[3*x+0] = 255-ptr[3*x+0]; + ptr[3*x+1] = 255-ptr[3*x+1]; + ptr[3*x+2] = 255-ptr[3*x+2]; + } + } } -int fb_font_width(void) +/* ---------------------------------------------------------------------- */ +/* shadow framebuffer -- text rendering */ + +static void shadow_draw_glyph(FT_Bitmap *bitmap, int sx, int sy) { - return f->width; + unsigned char *src,*dst; + unsigned int bit; + int x,y; + + src = bitmap->buffer; + for (y = 0; y < bitmap->rows; y++, src += bitmap->pitch) { + if (sy+y < 0) + continue; + if (sy+y >= sheight) + continue; + sdirty[sy+y]++; + dst = shadow[sy+y] + sx*3; + switch (bitmap->pixel_mode) { + case FT_PIXEL_MODE_MONO: + for (x = 0; x < bitmap->width; x++, dst += 3) { + if (sx+x < 0) + continue; + if (sx+x >= swidth) + continue; + bit = (1 << (7-(x&7))); + if (bit & (src[x >> 3])) { + dst[0] = 255; + dst[1] = 255; + dst[2] = 255; + } + } + break; + case FT_PIXEL_MODE_GRAY: + for (x = 0; x < bitmap->width; x++, dst += 3) { + if (sx+x < 0) + continue; + if (sx+x >= swidth) + continue; + if (src[x]) { + dst[0] += (255-dst[0]) * src[x] / 255; + dst[1] += (255-dst[1]) * src[x] / 255; + dst[2] += (255-dst[2]) * src[x] / 255; + } + } + break; + } + } } -void fb_status_line(unsigned char *msg) +struct glyph { + FT_Glyph glyph; + int pos; +}; + +int shadow_draw_string(FT_Face face, int x, int y, wchar_t *str, int align) { - int y; + struct glyph *glyphs; + FT_UInt gi,pgi; + FT_Vector delta,pen; + FT_Glyph image; + FT_BitmapGlyph bit; + size_t len; + int i,ng,pos,kerning; + + len = wcslen(str); + glyphs = malloc(sizeof(*glyphs) * len); + memset(glyphs,0,sizeof(*glyphs) * len); + + kerning = FT_HAS_KERNING(face); + pgi = 0; - if (!visible) - return; - y = fb_var.yres - f->height - ys; - fb_memset(fb_mem + fb_fix.line_length * y, 0, - fb_fix.line_length * (f->height+ys)); - fb_line(0, fb_var.xres, y, y); - fs_puts(f, 0, y+ys, msg); + for (ng = 0, pos = 0, i = 0; str[i] != 0; i++) { + gi = FT_Get_Char_Index(face, str[i]); + if (kerning && pgi && gi) { + FT_Get_Kerning(face,pgi,gi,FT_KERNING_DEFAULT,&delta); + pos += delta.x; + } + glyphs[ng].pos = pos; + if (0 != FT_Load_Glyph(face, gi, FT_LOAD_DEFAULT)) + continue; + if (0 != FT_Get_Glyph(face->glyph, &glyphs[ng].glyph)) + continue; + pos += face->glyph->advance.x; + pgi = gi; + ng++; + } + + for (i = 0; i < ng; i++) { + pen.x = (x << 6) + glyphs[i].pos; + pen.y = (sheight - y) << 6; + switch(align) { + case -1: /* left */ + break; + case 0: /* center */ + pen.x -= pos/2; + break; + case 1: /* right */ + pen.x -= pos; + break; + } + image = glyphs[i].glyph; + if (0 != FT_Glyph_To_Bitmap(&image,FT_RENDER_MODE_NORMAL,&pen,0)) + continue; + bit = (FT_BitmapGlyph)image; + shadow_draw_glyph(&bit->bitmap, bit->left, sheight - bit->top); + FT_Done_Glyph(image); + } + + for (i = 0; i < ng; i++) { + FT_Done_Glyph(glyphs[i].glyph); + } + free(glyphs); + + return pos >> 6; } -void fb_edit_line(unsigned char *str, int pos) +void shadow_draw_string_cursor(FT_Face face, int x, int y, wchar_t *str, int pos) { - int x,y; - - if (!visible) - return; - y = fb_var.yres - f->height - ys; - x = pos * f->width; - fb_memset(fb_mem + fb_fix.line_length * y, 0, - fb_fix.line_length * (f->height+ys)); - fb_line(0, fb_var.xres, y, y); - fs_puts(f, 0, y+ys, str); - fb_line(x, x + f->width, fb_var.yres-1, fb_var.yres-1); - fb_line(x, x + f->width, fb_var.yres-2, fb_var.yres-2); + wchar_t save; + int len, left, width, y1, y2; + + len = wcslen(str); + if (pos >= len) { + left = shadow_draw_string(face, x, y, str, -1); + width = shadow_draw_string(face, x+left, y, L" ", -1); + } else { + save = str[pos]; + str[pos] = 0; + left = shadow_draw_string(face, x, y, str, -1); + str[pos] = save; + + save = str[pos+1]; + str[pos+1] = 0; + width = shadow_draw_string(face, x+left, y, str+pos, -1); + str[pos+1] = save; + + shadow_draw_string(face, x+left+width, y, str+pos+1, -1); + } + + y2 = y - (face->size->metrics.descender >> 6) -1; + y1 = y2 - (face->size->metrics.height >> 6) +1; + shadow_reverse(left,left+width,y1,y2); } -void fb_text_box(int x, int y, char *lines[], unsigned int count) +void shadow_draw_text_box(FT_Face face, int x, int y, int percent, wchar_t *lines[], unsigned int count) { unsigned int i,len,max, x1, x2, y1, y2; @@ -167,23 +524,107 @@ void fb_text_box(int x, int y, char *lines[], unsigned int count) max = 0; for (i = 0; i < count; i++) { - len = strlen(lines[i]); + len = wcslen(lines[i]); if (max < len) max = len; } + + FT_Load_Glyph(face, FT_Get_Char_Index(face, 'm'), FT_LOAD_DEFAULT); x1 = x; - x2 = x + max * f->width; + x2 = x + max * (face->glyph->advance.x >> 6); y1 = y; - y2 = y + count * f->height; + y2 = y + count * (face->size->metrics.height >> 6); x += xs; x2 += 2*xs; y += ys; y2 += 2*ys; + y += (face->size->metrics.height >> 6); + y += (face->size->metrics.descender >> 6); - fb_clear_rect(x1, x2, y1, y2); - fb_rect(x1, x2, y1, y2); + shadow_darkify(x1, x2, y1, y2, percent); + shadow_draw_rect(x1, x2, y1, y2); for (i = 0; i < count; i++) { - fs_puts(f,x,y,lines[i]); - y += f->height; + shadow_draw_string(face, x, y, lines[i], -1); + y += (face->size->metrics.height >> 6); } } +/* ---------------------------------------------------------------------- */ +/* fontconfig + freetype font rendering */ + +static FT_Library freetype; + +void font_init(void) +{ + int rc; + + FcInit(); + rc = FT_Init_FreeType(&freetype); + if (rc) { + fprintf(stderr,"FT_Init_FreeType() failed\n"); + exit(1); + } +} + +FT_Face font_open(char *fcname) +{ + FcResult result = 0; + FT_Face face = NULL; + FcPattern *pattern,*match; + char *fontname,*h; + FcChar8 *filename; + double pixelsize; + int rc; + + /* parse + match font name */ + pattern = FcNameParse(fcname); + FcConfigSubstitute(NULL, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + match = FcFontMatch (0, pattern, &result); + FcPatternDestroy(pattern); + if (FcResultMatch != result) + return NULL; + fontname = FcNameUnparse(match); + h = strchr(fontname, ':'); + if (h) + *h = 0; + + /* try get the face directly */ + result = FcPatternGetFTFace(match, FC_FT_FACE, 0, &face); + if (FcResultMatch == result) { + fprintf(stderr,"using \"%s\", face=%p\n",fontname,face); + return face; + } + + /* failing that use the filename */ + result = FcPatternGetString (match, FC_FILE, 0, &filename); + if (FcResultMatch == result) { + result = FcPatternGetDouble(match, FC_PIXEL_SIZE, 0, &pixelsize); + if (FcResultMatch != result) + pixelsize = 16; + fprintf(stderr,"using \"%s\", pixelsize=%.2lf file=%s\n", + fontname,pixelsize,filename); + rc = FT_New_Face (freetype, filename, 0, &face); + if (rc) + return NULL; + FT_Set_Pixel_Sizes(face, 0, (int)pixelsize); + return face; + } + + /* oops, didn't work */ + return NULL; +} + +/* ---------------------------------------------------------------------- */ +/* clear screen (areas) */ + +void fb_clear_mem(void) +{ + if (visible) + fb_memset(fb_mem,0,fb_fix.smem_len); +} + +void fb_clear_screen(void) +{ + if (visible) + fb_memset(fb_mem,0,fb_fix.line_length * fb_var.yres); +} @@ -1,11 +1,29 @@ +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_GLYPH_H + extern int visible; +void shadow_render(void); +void shadow_clear_lines(int first, int last); +void shadow_clear(void); +void shadow_set_palette(int fd); +void shadow_init(void); +void shadow_fini(void); + +void shadow_draw_line(int x1, int x2, int y1,int y2); +void shadow_draw_rect(int x1, int x2, int y1,int y2); +void shadow_draw_rgbdata(int x, int y, int pixels, unsigned char *rgb); +void shadow_darkify(int x1, int x2, int y1,int y2, int percent); +void shadow_reverse(int x1, int x2, int y1,int y2); + +int shadow_draw_string(FT_Face face, int x, int y, wchar_t *str, int align); +void shadow_draw_string_cursor(FT_Face face, int x, int y, wchar_t *str, int pos); +void shadow_draw_text_box(FT_Face face, int x, int y, int percent, + wchar_t *lines[], unsigned int count); + +void font_init(void); +FT_Face font_open(char *fcname); + void fb_clear_mem(void); void fb_clear_screen(void); - -void fb_text_init1(char *font); -void fb_text_init2(void); -int fb_font_width(void); -void fb_status_line(unsigned char *msg); -void fb_edit_line(unsigned char *str, int pos); -void fb_text_box(int x, int y, char *lines[], unsigned int count); @@ -19,6 +19,7 @@ #include <signal.h> #include <ctype.h> #include <locale.h> +#include <wchar.h> #include <sys/time.h> #include <sys/ioctl.h> #include <sys/mman.h> @@ -112,9 +113,10 @@ static float fbgamma = 1; /* Command line options. */ -int autodown = 0; -int autoup = 0; -int comments = 0; +int autodown = 0; +int autoup = 0; +int comments = 0; +int transparency = 30; struct option fbi_options[] = { {"version", no_argument, NULL, 'V'}, /* version */ @@ -146,6 +148,7 @@ struct option fbi_options[] = { /* font handling */ static char *fontname = NULL; +static FT_Face face; /* ---------------------------------------------------------------------- */ @@ -335,32 +338,101 @@ static void flist_print_tagged(FILE *fp) /* ---------------------------------------------------------------------- */ -static void status(unsigned char *desc, char *info) +static void +shadow_draw_image(struct ida_image *img, int xoff, int yoff, + unsigned int first, unsigned int last) { - int chars, ilen; - char *str; + unsigned int dwidth = MIN(img->i.width, fb_var.xres); + unsigned int dheight = MIN(img->i.height, fb_var.yres); + unsigned int data, offset, y, xs, ys; + + shadow_clear_lines(first, last); + + /* offset for image data (image > screen, select visible area) */ + offset = (yoff * img->i.width + xoff) * 3; + + /* offset for video memory (image < screen, center image) */ + xs = 0, ys = 0; + if (img->i.width < fb_var.xres) + xs += (fb_var.xres - img->i.width) / 2; + if (img->i.height < fb_var.yres) + ys += (fb_var.yres - img->i.height) / 2; + + /* go ! */ + for (data = 0, y = 0; + data < img->i.width * img->i.height * 3 + && data / img->i.width / 3 < dheight; + data += img->i.width * 3, y++) { + if (ys+y < first) + continue; + if (ys+y > last) + continue; + shadow_draw_rgbdata(xs, ys+y, dwidth, img->data + data + offset); + } +} + +static void status_prepare(struct ida_image *img) +{ + int y1 = fb_var.yres - (face->size->metrics.height >> 6); + int y2 = fb_var.yres - 1; + + if (img) { + shadow_draw_image(img, left, top, y1, y2); + shadow_darkify(0, fb_var.xres-1, y1, y2, transparency); + } else { + shadow_clear_lines(y1, y2); + } + shadow_draw_line(0, fb_var.xres-1, y1-1, y1-1); +} + +static void status_update(struct ida_image *img, unsigned char *desc, char *info) +{ + int yt = fb_var.yres + (face->size->metrics.descender >> 6); + wchar_t str[128]; if (!statusline) return; - chars = fb_var.xres / fb_font_width(); - str = malloc(chars+1); + status_prepare(img); + + swprintf(str,sizeof(str),L"%s",desc); + shadow_draw_string(face, 0, yt, str, -1); if (info) { - ilen = strlen(info); - sprintf(str, "%-*.*s [ %s ] H - Help", - chars-14-ilen, chars-14-ilen, desc, info); + swprintf(str,sizeof(str), L"[ %s ] H - Help", info); } else { - sprintf(str, "%-*.*s | H - Help", chars-11, chars-11, desc); + swprintf(str,sizeof(str), L"| H - Help"); } - fb_status_line(str); - free(str); + shadow_draw_string(face, fb_var.xres, yt, str, 1); + + shadow_render(); } -static void show_error(unsigned char *msg) +static void status_error(unsigned char *msg) { - fb_status_line(msg); + int yt = fb_var.yres + (face->size->metrics.descender >> 6); + wchar_t str[128]; + + status_prepare(NULL); + + swprintf(str,sizeof(str), L"%s", msg); + shadow_draw_string(face, 0, yt, str, -1); + + shadow_render(); sleep(2); } +static void status_edit(struct ida_image *img, unsigned char *msg, int pos) +{ + int yt = fb_var.yres + (face->size->metrics.descender >> 6); + wchar_t str[128]; + + status_prepare(img); + + swprintf(str,sizeof(str), L"%s", msg); + shadow_draw_string_cursor(face, 0, yt, str, pos); + + shadow_render(); +} + static void show_exif(struct flist *f) { static unsigned int tags[] = { @@ -383,14 +455,14 @@ static void show_exif(struct flist *f) unsigned int tag,l1,l2,len,count,i; const char *title[ARRAY_SIZE(tags)]; char *value[ARRAY_SIZE(tags)]; - char *linebuffer[ARRAY_SIZE(tags)]; + wchar_t *linebuffer[ARRAY_SIZE(tags)]; if (!visible) return; ed = exif_data_new_from_file(f->name); if (NULL == ed) { - status("image has no EXIF data", NULL); + status_error("image has no EXIF data"); return; } @@ -421,13 +493,16 @@ static void show_exif(struct flist *f) for (tag = 0; tag < ARRAY_SIZE(tags); tag++) { if (NULL == title[tag]) continue; - linebuffer[count] = malloc(l1+l2+8); - sprintf(linebuffer[count],"%-*.*s : %-*.*s", - l1, l1, title[tag], - l2, l2, value[tag]); + linebuffer[count] = malloc(sizeof(wchar_t)*(l1+l2+8)); + swprintf(linebuffer[count], l1+l2+8, + L"%-*.*s : %-*.*s", + l1, l1, title[tag], + l2, l2, value[tag]); count++; } - fb_text_box(24,16,linebuffer,count); + shadow_draw_text_box(face, 24, 16, transparency, + linebuffer, count); + shadow_render(); /* pass three -- free data */ for (tag = 0; tag < ARRAY_SIZE(tags); tag++) @@ -440,29 +515,31 @@ static void show_exif(struct flist *f) static void show_help(void) { - static char *help[] = { - "keyboard commands", - "~~~~~~~~~~~~~~~~~", - " ESC, Q - quit", - " pgdn, space - next image", - " pgup - previous image", - " +/- - zoom in/out", - " A - autozoom image", - " cursor keys - scroll image", - "", - " H - show this help text", - " I - show EXIF info", - " P - pause slideshow", - " V - toggle statusline", - "", - "available if started with --edit switch,", - "rotation works for jpeg images only:", - " shift+D - delete image", - " R - rotate clockwise", - " L - rotate counter-clockwise", + static wchar_t *help[] = { + L"keyboard commands", + L"~~~~~~~~~~~~~~~~~", + L" ESC, Q - quit", + L" pgdn, space - next image", + L" pgup - previous image", + L" +/- - zoom in/out", + L" A - autozoom image", + L" cursor keys - scroll image", + L"", + L" H - show this help text", + L" I - show EXIF info", + L" P - pause slideshow", + L" V - toggle statusline", + L"", + L"available if started with --edit switch,", + L"rotation works for jpeg images only:", + L" shift+D - delete image", + L" R - rotate clockwise", + L" L - rotate counter-clockwise", }; - fb_text_box(24,16,help,ARRAY_SIZE(help)); + shadow_draw_text_box(face, 24, 16, transparency, + help, ARRAY_SIZE(help)); + shadow_render(); } /* ---------------------------------------------------------------------- */ @@ -504,7 +581,7 @@ static void debug_key(char *key) len += sprintf(linebuffer+len, "%s%c", key[i] < 0x20 ? "^" : "", key[i] < 0x20 ? key[i] + 0x40 : key[i]); - status(linebuffer, NULL); + status_update(NULL, linebuffer, NULL); } static void @@ -522,9 +599,9 @@ console_switch(int is_busy) visible = 1; redraw = 1; ioctl(fd,FBIOPAN_DISPLAY,&fb_var); - fb_clear_screen(); + shadow_clear(); if (is_busy) - status("busy, please wait ...", NULL); + status_update(NULL, "busy, please wait ...", NULL); break; default: break; @@ -650,167 +727,6 @@ static float auto_scale(struct ida_image *img) /* ---------------------------------------------------------------------- */ -static unsigned char * -convert_line(int bpp, int line, int owidth, - char unsigned *dest, char unsigned *buffer) -{ - unsigned char *ptr = (void*)dest; - unsigned short *ptr2 = (void*)dest; - unsigned long *ptr4 = (void*)dest; - int x; - - switch (fb_var.bits_per_pixel) { - case 8: - dither_line(buffer, ptr, line, owidth); - ptr += owidth; - return ptr; - case 15: - case 16: - for (x = 0; x < owidth; x++) { - ptr2[x] = lut_red[buffer[x*3]] | - lut_green[buffer[x*3+1]] | - lut_blue[buffer[x*3+2]]; - } - ptr2 += owidth; - return (char*)ptr2; - case 24: - for (x = 0; x < owidth; x++) { - ptr[3*x+2] = buffer[3*x+0]; - ptr[3*x+1] = buffer[3*x+1]; - ptr[3*x+0] = buffer[3*x+2]; - } - ptr += owidth * 3; - return ptr; - case 32: - for (x = 0; x < owidth; x++) { - ptr4[x] = lut_red[buffer[x*3]] | - lut_green[buffer[x*3+1]] | - lut_blue[buffer[x*3+2]]; - } - ptr4 += owidth; - return (char*)ptr4; - default: - /* keep compiler happy */ - return NULL; - } -} - -/* ---------------------------------------------------------------------- */ - -static void init_one(int32_t *lut, int bits, int shift) -{ - int i; - - if (bits > 8) - for (i = 0; i < 256; i++) - lut[i] = (i << (bits + shift - 8)); - else - for (i = 0; i < 256; i++) - lut[i] = (i >> (8 - bits)) << shift; -} - -static void -lut_init(int depth) -{ - if (fb_var.red.length && - fb_var.green.length && - fb_var.blue.length) { - /* fb_var.{red|green|blue} looks sane, use it */ - init_one(lut_red, fb_var.red.length, fb_var.red.offset); - init_one(lut_green, fb_var.green.length, fb_var.green.offset); - init_one(lut_blue, fb_var.blue.length, fb_var.blue.offset); - } else { - /* fallback */ - int i; - switch (depth) { - case 15: - for (i = 0; i < 256; i++) { - lut_red[i] = (i & 0xf8) << 7; /* bits -rrrrr-- -------- */ - lut_green[i] = (i & 0xf8) << 2; /* bits ------gg ggg----- */ - lut_blue[i] = (i & 0xf8) >> 3; /* bits -------- ---bbbbb */ - } - break; - case 16: - for (i = 0; i < 256; i++) { - lut_red[i] = (i & 0xf8) << 8; /* bits rrrrr--- -------- */ - lut_green[i] = (i & 0xfc) << 3; /* bits -----ggg ggg----- */ - lut_blue[i] = (i & 0xf8) >> 3; /* bits -------- ---bbbbb */ - } - break; - case 24: - for (i = 0; i < 256; i++) { - lut_red[i] = i << 16; /* byte -r-- */ - lut_green[i] = i << 8; /* byte --g- */ - lut_blue[i] = i; /* byte ---b */ - } - break; - } - } -} - -static unsigned short calc_gamma(int n, int max) -{ - int ret =65535.0 * pow((float)n/(max), 1 / fbgamma); - if (ret > 65535) ret = 65535; - if (ret < 0) ret = 0; - return ret; -} - -static void -linear_palette(int bit) -{ - int i, size = 256 >> (8 - bit); - - for (i = 0; i < size; i++) - red[i] = green[i] = blue[i] = calc_gamma(i,size); -} - -static void -svga_dither_palette(int r, int g, int b) -{ - int rs, gs, bs, i; - - rs = 256 / (r - 1); - gs = 256 / (g - 1); - bs = 256 / (b - 1); - for (i = 0; i < 256; i++) { - red[i] = calc_gamma(rs * ((i / (g * b)) % r), 255); - green[i] = calc_gamma(gs * ((i / b) % g), 255); - blue[i] = calc_gamma(bs * ((i) % b), 255); - } -} - -static void -svga_display_image(struct ida_image *img, int xoff, int yoff) -{ - unsigned int dwidth = MIN(img->i.width, fb_var.xres); - unsigned int dheight = MIN(img->i.height, fb_var.yres); - unsigned int data, video, bank, offset, bytes, y; - - if (!visible) - return; - bytes = (fb_var.bits_per_pixel+7)/8; - - /* offset for image data (image > screen, select visible area) */ - offset = (yoff * img->i.width + xoff) * 3; - - /* offset for video memory (image < screen, center image) */ - video = 0, bank = 0; - if (img->i.width < fb_var.xres) - video += bytes * ((fb_var.xres - img->i.width) / 2); - if (img->i.height < fb_var.yres) - video += fb_fix.line_length * ((fb_var.yres - img->i.height) / 2); - - /* go ! */ - for (data = 0, y = 0; - data < img->i.width * img->i.height * 3 - && data / img->i.width / 3 < dheight; - data += img->i.width * 3, video += fb_fix.line_length) { - convert_line(fb_var.bits_per_pixel, y++, dwidth, - fb_mem+video, img->data + data + offset); - } -} - static int svga_show(struct ida_image *img, int timeout, char *desc, char *info, int *nr) { @@ -831,8 +747,12 @@ svga_show(struct ida_image *img, int timeout, char *desc, char *info, int *nr) /* start with centered image, if larger than screen */ if (img->i.width > fb_var.xres) left = (img->i.width - fb_var.xres) / 2; - if (img->i.height > fb_var.yres && !textreading) - top = (img->i.height - fb_var.yres) / 2; + if (img->i.height > fb_var.yres) { + if (textreading) + top = 0; + else + top = (img->i.height - fb_var.yres) / 2; + } new_image = 0; } @@ -856,8 +776,9 @@ svga_show(struct ida_image *img, int timeout, char *desc, char *info, int *nr) if (left + fb_var.xres > img->i.width) left = img->i.width - fb_var.xres; } - svga_display_image(img, left, top); - status(desc, info); + shadow_draw_image(img, left, top, 0, fb_var.yres-1); + status_update(img, desc, info); + shadow_render(); } if (switch_last != fb_switch_state) { console_switch(0); @@ -958,7 +879,7 @@ svga_show(struct ida_image *img, int timeout, char *desc, char *info, int *nr) 0 == strcmp(key, "P")) { if (-1 != timeout) { paused = !paused; - status(paused ? "pause on " : "pause off", NULL); + status_update(img, paused ? "pause on " : "pause off", NULL); } } else if (0 == strcmp(key, "D")) { @@ -1007,9 +928,8 @@ svga_show(struct ida_image *img, int timeout, char *desc, char *info, int *nr) } else if (rc == 1 && *key >= '0' && *key <= '9') { *nr = *nr * 10 + (*key - '0'); sprintf(linebuffer, "> %d",*nr); - status(linebuffer, NULL); + status_update(img, linebuffer, NULL); } else { - *nr = 0; #if 0 debug_key(key); @@ -1082,7 +1002,6 @@ static char *make_desc(struct ida_image_info *img, char *filename) snprintf(linebuffer+len,sizeof(linebuffer)-len, " (%s)", my_basename(filename)); } - return linebuffer; } @@ -1099,7 +1018,7 @@ static char *make_info(struct ida_image *img, float scale) return linebuffer; } -static char edit_line(char *line, int max) +static char edit_line(struct ida_image *img, char *line, int max) { int len = strlen(line); int pos = len; @@ -1108,7 +1027,11 @@ static char edit_line(char *line, int max) fd_set set; do { +#if 0 fb_edit_line(line,pos); +#else + status_edit(img,line,pos); +#endif FD_SET(0, &set); rc = select(1, &set, NULL, NULL, NULL); @@ -1180,7 +1103,7 @@ static char edit_line(char *line, int max) } while (1); } -static void edit_desc(char *filename) +static void edit_desc(struct ida_image *img, char *filename) { static char linebuffer[128]; char *desc; @@ -1192,7 +1115,7 @@ static void edit_desc(char *filename) linebuffer[0] = 0; len = 0; } - rc = edit_line(linebuffer, sizeof(linebuffer)-1); + rc = edit_line(img, linebuffer, sizeof(linebuffer)-1); if (0 != rc) return; desktop_write_entry(desc, "Directory", "Comment=", linebuffer); @@ -1202,6 +1125,7 @@ static void edit_desc(char *filename) static void cleanup_and_exit(int code) { + shadow_fini(); fb_clear_mem(); tty_restore(); fb_cleanup(); @@ -1226,7 +1150,7 @@ main(int argc, char *argv[]) float newscale = 1; int c, editable = 0, once = 0; - int need_read, need_refresh; + int need_read; int i, arg, key; char *line, *info, *desc; @@ -1338,56 +1262,17 @@ main(int argc, char *argv[]) if (randomize != -1) flist_randomize(); fcurrent = flist_first(); - need_read = 1; - need_refresh = 1; - fb_text_init1(fontname); + font_init(); + face = font_open("monospace:size=16"); fd = fb_init(fbdev, fbmode, vt); fb_catch_exit_signals(); fb_switch_init(); + shadow_init(); + shadow_set_palette(fd); signal(SIGTSTP,SIG_IGN); - fb_text_init2(); - switch (fb_var.bits_per_pixel) { - case 8: - svga_dither_palette(8, 8, 4); - dither = TRUE; - init_dither(8, 8, 4, 2); - dither_line = dither_line_color; - break; - case 15: - case 16: - if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR) - linear_palette(5); - if (fb_var.green.length == 5) { - lut_init(15); - } else { - lut_init(16); - } - break; - case 24: - if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR) - linear_palette(8); - break; - case 32: - if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR) - linear_palette(8); - lut_init(24); - break; - default: - fprintf(stderr, "Oops: %i bit/pixel ???\n", - fb_var.bits_per_pixel); - exit(1); - } - if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR || - fb_var.bits_per_pixel == 8) { - if (-1 == ioctl(fd,FBIOPUTCMAP,&cmap)) { - perror("ioctl FBIOPUTCMAP"); - exit(1); - } - } - /* svga main loop */ tty_raw(); desc = NULL; @@ -1395,14 +1280,14 @@ main(int argc, char *argv[]) for (;;) { if (need_read) { need_read = 0; - need_refresh = 1; - sprintf(linebuffer,"loading %s ...",fcurrent->name); - status(linebuffer, NULL); free_image(fimg); free_image(simg); - fimg = read_image(fcurrent->name); + fimg = NULL; simg = NULL; img = NULL; + sprintf(linebuffer,"loading %s ...",fcurrent->name); + status_update(img,linebuffer, NULL); + fimg = read_image(fcurrent->name); scale = 1; if (fimg) { if (autoup || autodown) { @@ -1415,7 +1300,7 @@ main(int argc, char *argv[]) if (scale != 1) { sprintf(linebuffer,"scaling (%.0f%%) %s ...", scale*100, fcurrent->name); - status(linebuffer, NULL); + status_update(img,linebuffer, NULL); simg = scale_image(fimg,scale); img = simg; } else { @@ -1425,17 +1310,11 @@ main(int argc, char *argv[]) } if (!img) { sprintf(linebuffer,"%s: FAILED",fcurrent->name); - show_error(linebuffer); + status_error(linebuffer); } } - if (img) { - if (need_refresh) { - need_refresh = 0; - if (img->i.width < fb_var.xres || img->i.height < fb_var.yres) - fb_clear_screen(); - } + if (img) info = make_info(fimg,scale); - } switch (key = svga_show(img, timeout, desc, info, &arg)) { case KEY_DELETE: if (editable) { @@ -1450,13 +1329,10 @@ main(int argc, char *argv[]) need_read = 1; if (list_empty(&flist)) { /* deleted last one */ - fb_clear_mem(); - tty_restore(); - fb_cleanup(); - exit(0); + cleanup_and_exit(0); } } else { - show_error("readonly mode, sorry [start with --edit?]"); + status_error("readonly mode, sorry [start with --edit?]"); } break; case KEY_ROT_CW: @@ -1464,7 +1340,7 @@ main(int argc, char *argv[]) { if (editable) { sprintf(linebuffer,"rotating %s ...",fcurrent->name); - status(linebuffer, NULL); + status_update(img, linebuffer, NULL); jpeg_transform_inplace (fcurrent->name, (key == KEY_ROT_CW) ? JXFORM_ROT_90 : JXFORM_ROT_270, @@ -1477,7 +1353,7 @@ main(int argc, char *argv[]) JFLAG_UPDATE_ORIENTATION); need_read = 1; } else { - show_error("readonly mode, sorry [start with --edit?]"); + status_error("readonly mode, sorry [start with --edit?]"); } break; } @@ -1507,9 +1383,7 @@ main(int argc, char *argv[]) need_read = 1; fcurrent = flist_next(fcurrent,once,1); if (NULL == fcurrent) { - fb_clear_mem(); - tty_restore(); - fb_cleanup(); + cleanup_and_exit(0); } /* FIXME: wrap around */ break; @@ -1534,11 +1408,10 @@ main(int argc, char *argv[]) scale = newscale; sprintf(linebuffer,"scaling (%.0f%%) %s ...", scale*100, fcurrent->name); - status(linebuffer, NULL); + status_update(NULL, linebuffer, NULL); free_image(simg); simg = scale_image(fimg,scale); img = simg; - need_refresh = 1; break; case KEY_GOTO: if (arg > 0 && arg <= fcount) { @@ -1555,11 +1428,10 @@ main(int argc, char *argv[]) } #endif statusline = !statusline; - need_refresh = 1; break; case KEY_DESC: if (!comments) { - edit_desc(fcurrent->name); + edit_desc(img, fcurrent->name); desc = make_desc(&fimg->i,fcurrent->name); } break; @@ -1,502 +0,0 @@ -/* - * text rendering for the framebuffer console - * pick fonts from X11 font server or - * use linux consolefont psf files. - * (c) 2001 Gerd Knorr <kraxel@bytesex.org> - */ -#include "config.h" - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <linux/fb.h> - -#include "fbtools.h" -#include "fs.h" - -/* ------------------------------------------------------------------ */ - -#define BIT_ORDER BitmapFormatBitOrderMSB -#ifdef BYTE_ORDER -#undef BYTE_ORDER -#endif -#define BYTE_ORDER BitmapFormatByteOrderMSB -#define SCANLINE_UNIT BitmapFormatScanlineUnit8 -#define SCANLINE_PAD BitmapFormatScanlinePad8 -#define EXTENTS BitmapFormatImageRectMin - -#define SCANLINE_PAD_BYTES 1 -#define GLWIDTHBYTESPADDED(bits, nBytes) \ - ((nBytes) == 1 ? (((bits) + 7) >> 3) /* pad to 1 byte */\ - :(nBytes) == 2 ? ((((bits) + 15) >> 3) & ~1) /* pad to 2 bytes */\ - :(nBytes) == 4 ? ((((bits) + 31) >> 3) & ~3) /* pad to 4 bytes */\ - :(nBytes) == 8 ? ((((bits) + 63) >> 3) & ~7) /* pad to 8 bytes */\ - : 0) - -static const unsigned fs_masktab[] = { - (1 << 7), (1 << 6), (1 << 5), (1 << 4), - (1 << 3), (1 << 2), (1 << 1), (1 << 0), -}; - -/* ------------------------------------------------------------------ */ - -#ifndef X_DISPLAY_MISSING -static FSServer *svr; -#endif -unsigned int fs_bpp, fs_black, fs_white; - -void (*fs_setpixel)(void *ptr, unsigned int color); - -static void setpixel1(void *ptr, unsigned int color) -{ - unsigned char *p = ptr; - *p = color; -} -static void setpixel2(void *ptr, unsigned int color) -{ - unsigned short *p = ptr; - *p = color; -} -static void setpixel3(void *ptr, unsigned int color) -{ - unsigned char *p = ptr; - *(p++) = (color >> 16) & 0xff; - *(p++) = (color >> 8) & 0xff; - *(p++) = color & 0xff; -} -static void setpixel4(void *ptr, unsigned int color) -{ - unsigned long *p = ptr; - *p = color; -} - -int fs_init_fb(int white8) -{ - switch (fb_var.bits_per_pixel) { - case 8: - fs_white = white8; fs_black = 0; fs_bpp = 1; - fs_setpixel = setpixel1; - break; - case 15: - case 16: - if (fb_var.green.length == 6) - fs_white = 0xffff; - else - fs_white = 0x7fff; - fs_black = 0; fs_bpp = 2; - fs_setpixel = setpixel2; - break; - case 24: - fs_white = 0xffffff; fs_black = 0; fs_bpp = fb_var.bits_per_pixel/8; - fs_setpixel = setpixel3; - break; - case 32: - fs_white = 0xffffff; fs_black = 0; fs_bpp = fb_var.bits_per_pixel/8; - fs_setpixel = setpixel4; - break; - default: - fprintf(stderr, "Oops: %i bit/pixel ???\n", - fb_var.bits_per_pixel); - return -1; - } - return 0; -} - -void fs_render_fb(unsigned char *ptr, int pitch, - FSXCharInfo *charInfo, unsigned char *data) -{ - int row,bit,bpr,x; - - bpr = GLWIDTHBYTESPADDED((charInfo->right - charInfo->left), - SCANLINE_PAD_BYTES); - for (row = 0; row < (charInfo->ascent + charInfo->descent); row++) { - for (x = 0, bit = 0; bit < (charInfo->right - charInfo->left); bit++) { - if (data[bit>>3] & fs_masktab[bit&7]) - fs_setpixel(ptr+x,fs_white); - x += fs_bpp; - } - data += bpr; - ptr += pitch; - } -} - -int fs_puts(struct fs_font *f, unsigned int x, unsigned int y, - unsigned char *str) -{ - unsigned char *pos,*start; - int i,c,j,w; - - pos = fb_mem+fb_mem_offset; - pos += fb_fix.line_length * y; - for (i = 0; str[i] != '\0'; i++) { - c = str[i]; - if (NULL == f->eindex[c]) - continue; - /* clear with bg color */ - start = pos + x*fs_bpp + f->fontHeader.max_bounds.descent * fb_fix.line_length; - w = (f->eindex[c]->width+1)*fs_bpp; - for (j = 0; j < f->height; j++) { - memset(start,0,w); - start += fb_fix.line_length; - } - /* draw char */ - start = pos + x*fs_bpp + fb_fix.line_length * (f->height-f->eindex[c]->ascent); - fs_render_fb(start,fb_fix.line_length,f->eindex[c],f->gindex[c]); - x += f->eindex[c]->width; - if (x > fb_var.xres - f->width) - return -1; - } - return x; -} - -int fs_textwidth(struct fs_font *f, unsigned char *str) -{ - int width = 0; - int i,c; - - for (i = 0; str[i] != '\0'; i++) { - c = str[i]; - if (NULL == f->eindex[c]) - continue; - width += f->eindex[c]->width; - } - return width; -} - -void fs_render_tty(FSXCharInfo *charInfo, unsigned char *data) -{ - int bpr,row,bit,on; - - bpr = GLWIDTHBYTESPADDED((charInfo->right - charInfo->left), - SCANLINE_PAD_BYTES); - for (row = 0; row < (charInfo->ascent + charInfo->descent); row++) { - fprintf(stdout,"|"); - for (bit = 0; bit < (charInfo->right - charInfo->left); bit++) { - on = data[bit>>3] & fs_masktab[bit&7]; - fprintf(stdout,"%s",on ? "##" : " "); - } - fprintf(stdout,"|\n"); - data += bpr; - } - fprintf(stdout,"--\n"); -} - -/* ------------------------------------------------------------------ */ - -#ifndef X_DISPLAY_MISSING -/* connect to font server */ -int fs_connect(char *servername) -{ - if (NULL == servername) - servername = getenv("FONTSERVER"); - if (NULL == servername) - servername = "unix/:7100"; - svr = FSOpenServer(servername); - if (NULL == svr) { - if (NULL == FSServerName(servername)) { - fprintf(stderr, "no font server defined\n"); - } else { - fprintf(stderr, "unable to open server \"%s\"\n", - FSServerName(servername)); - } - return -1; - } - return 0; -} - -/* load font from font server */ -struct fs_font* fs_open(char *pattern) -{ - int nnames = 1; - int available,high,low,encoding,bpr; - char **fonts; - unsigned char *glyph; - Font dummy; - FSBitmapFormat format; - FSXCharInfo *charInfo; - struct fs_font *f = NULL; - - if (NULL == svr) { - fprintf(stderr,"fs: not connected\n"); - return NULL; - } - - fonts = FSListFonts(svr, pattern, nnames, &available); - if (0 == available) { - fprintf(stderr,"fs: font not available [%s]\n",pattern); - goto out; - } - fprintf(stderr,"using x11 font \"%s\"\n",fonts[0]); - - f = malloc(sizeof(*f)); - memset(f,0,sizeof(*f)); - f->font = FSOpenBitmapFont(svr, 0, 0, fonts[0], &dummy); - FSFreeFontNames(fonts); - if (0 == f->font) - goto out; - - FSQueryXInfo(svr,f->font,&f->fontHeader, &f->propInfo, - &f->propOffsets, &f->propData); - format = BYTE_ORDER | BIT_ORDER | SCANLINE_UNIT | SCANLINE_PAD | EXTENTS; - FSQueryXExtents16(svr, f->font, True, (FSChar2b *) 0, 0, &f->extents); - FSQueryXBitmaps16(svr, f->font, format, True, (FSChar2b *) 0, 0, - &f->offsets, &f->glyphs); - - f->maxenc = (f->fontHeader.char_range.max_char.high+1) << 8; - f->width = f->fontHeader.max_bounds.right - f->fontHeader.min_bounds.left; - f->height = f->fontHeader.max_bounds.ascent + f->fontHeader.max_bounds.descent; - f->eindex = malloc(f->maxenc * sizeof(FSXCharInfo*)); - f->gindex = malloc(f->maxenc * sizeof(unsigned char*)); - memset(f->eindex,0,f->maxenc * sizeof(FSXCharInfo*)); - memset(f->gindex,0,f->maxenc * sizeof(unsigned char*)); - - glyph = f->glyphs; - charInfo = f->extents; - for (high = f->fontHeader.char_range.min_char.high; - high <= f->fontHeader.char_range.max_char.high; - high++) { - for (low = f->fontHeader.char_range.min_char.low; - low <= f->fontHeader.char_range.max_char.low; - low++) { - bpr = GLWIDTHBYTESPADDED((charInfo->right - charInfo->left), - SCANLINE_PAD_BYTES); - encoding = (high<<8) + low; -#ifdef TTY - fprintf(stdout,"e=0x%x | w=%d l=%d r=%d | a=%d d=%d\n", - encoding,charInfo->width,charInfo->left, - charInfo->right,charInfo->ascent,charInfo->descent); -#endif - if ((charInfo->width != 0) || (charInfo->right != charInfo->left)) { - f->gindex[encoding] = glyph; - f->eindex[encoding] = charInfo; -#ifdef TTY - fs_render_tty(f->eindex[encoding], - f->gindex[encoding]); -#endif - } - glyph += (charInfo->descent + charInfo->ascent) * bpr; - charInfo++; - } - } - return f; - - out: - if (f) - fs_free(f); - return NULL; -} -#endif - -void fs_free(struct fs_font *f) -{ - if (f->gindex) - free(f->gindex); -#if 0 - if (f->extents) - FSFree((char *) f->extents); - if (f->offsets) - FSFree((char *) f->offsets); - if (f->propOffsets) - FSFree((char *) (f->propOffsets)); - if (f->propData) - FSFree((char *) (f->propData)); -#endif -#if 0 /* FIXME */ - if (f->glyphs) - FSFree((char *) f->glyphs); -#endif - free(f); -} - -/* ------------------------------------------------------------------ */ -/* load console font file */ - -static char *default_font[] = { - /* why the heck every f*cking distribution picks another - location for these fonts ??? */ - "/usr/share/consolefonts/lat1-16.psf", - "/usr/share/consolefonts/lat1-16.psf.gz", - "/usr/share/consolefonts/lat1-16.psfu.gz", - "/usr/share/kbd/consolefonts/lat1-16.psf", - "/usr/share/kbd/consolefonts/lat1-16.psf.gz", - "/usr/share/kbd/consolefonts/lat1-16.psfu.gz", - "/usr/lib/kbd/consolefonts/lat1-16.psf", - "/usr/lib/kbd/consolefonts/lat1-16.psf.gz", - "/usr/lib/kbd/consolefonts/lat1-16.psfu.gz", - "/lib/kbd/consolefonts/lat1-16.psf", - "/lib/kbd/consolefonts/lat1-16.psf.gz", - "/lib/kbd/consolefonts/lat1-16.psfu.gz", - NULL -}; - -struct fs_font* fs_consolefont(char **filename) -{ - int i; - char *h,command[256]; - struct fs_font *f = NULL; - FILE *fp; - - if (NULL == filename) - filename = default_font; - - for(i = 0; filename[i] != NULL; i++) { - if (-1 == access(filename[i],R_OK)) - continue; - break; - } - if (NULL == filename[i]) { - fprintf(stderr,"can't find console font file\n"); - return NULL; - } - - h = filename[i]+strlen(filename[i])-3; - if (0 == strcmp(h,".gz")) { - sprintf(command,"zcat %s",filename[i]); - fp = popen(command,"r"); - } else { - fp = fopen(filename[i], "r"); - } - if (NULL == fp) { - fprintf(stderr,"can't open %s: %s\n",filename[i],strerror(errno)); - return NULL; - } - - if (fgetc(fp) != 0x36 || - fgetc(fp) != 0x04) { - fprintf(stderr,"can't use font %s\n",filename[i]); - return NULL; - } - fprintf(stderr,"using linux console font \"%s\"\n",filename[i]); - - f = malloc(sizeof(*f)); - memset(f,0,sizeof(*f)); - - fgetc(fp); - f->maxenc = 256; - f->width = 8; - f->height = fgetc(fp); - f->fontHeader.min_bounds.left = 0; - f->fontHeader.max_bounds.right = f->width; - f->fontHeader.max_bounds.descent = 0; - f->fontHeader.max_bounds.ascent = f->height; - - f->glyphs = malloc(f->height * 256); - f->extents = malloc(sizeof(FSXCharInfo)*256); - fread(f->glyphs, 256, f->height, fp); - fclose(fp); - - f->eindex = malloc(sizeof(FSXCharInfo*) * 256); - f->gindex = malloc(sizeof(unsigned char*) * 256); - for (i = 0; i < 256; i++) { - f->eindex[i] = f->extents +i; - f->gindex[i] = f->glyphs +i * f->height; - f->eindex[i]->left = 0; - f->eindex[i]->right = 7; - f->eindex[i]->width = 8; - f->eindex[i]->descent = 0; - f->eindex[i]->ascent = f->height; - } - return f; -} - - -#ifdef TESTING -/* ------------------------------------------------------------------ */ -/* for testing */ - -int debug; - -/* list fonts */ -int fs_ls(char *pattern) -{ - int nnames = 16; - int available,i; - char **fonts; - - if (NULL == svr) { - fprintf(stderr,"fs: not connected\n"); - return -1; - } - - fonts = FSListFonts(svr, pattern, nnames, &available); - while (nnames <= available) { - nnames *= 2; - FSFreeFontNames(fonts); - fonts = FSListFonts(svr, pattern, nnames, &available); - } - for (i = 0; i < available; i++) { - fprintf(stderr,"%s\n",fonts[i]); - } - FSFreeFontNames(fonts); - return 0; -} - -void dump_charset(struct fs_font *f) -{ - unsigned char *pos; - int c,x,y; - - x = 0, y = 0; - for (c = 0; c < f->maxenc; c++) { - if (NULL == f->eindex[c]) - continue; - pos = fb_mem+fb_mem_offset; - pos += fb_fix.line_length * (y+f->height-f->eindex[c]->ascent); - pos += x*bpp; - fs_render_fb(pos,fb_fix.line_length,f->eindex[c],f->gindex[c]); - x += f->eindex[c]->right-f->eindex[c]->left+1; - if (x > fb_var.xres - f->width) { - x = 0; - y += f->height+1; - } - if (y > fb_var.yres - f->height) - break; - } -} - -int main(int argc, char *argv[]) -{ - struct fs_font *f = NULL; - unsigned char dummy[42]; - int fd; - - if (argc < 2) { - fprintf(stderr,"missing arg\n"); - exit(1); - } - - /* try font server */ - if (-1 != fs_connect(NULL)) { - fs_ls(argv[1]); - f = fs_open(argv[1]); - if (NULL == f) - fprintf(stderr,"no such font\n"); - } - - /* try console font */ - if (NULL == f) - f = fs_consolefont(NULL); - if (NULL == f) - exit(1); - -#ifdef TTY - exit(1); -#endif - - fd = fb_init(NULL, NULL, 0); - fb_cleanup_fork(); - fb_switch_init(); - fs_init_fb(); - - if (argc < 3) { - dump_charset(f); - } else { - fs_puts(f,0,0,argv[2]); - } - fgets(dummy,42,stdin); - - return 0; -} -#endif @@ -1,72 +0,0 @@ -#ifndef X_DISPLAY_MISSING -# include <FSlib.h> - -struct fs_font { - Font font; - FSXFontInfoHeader fontHeader; - FSPropInfo propInfo; - FSPropOffset *propOffsets; - unsigned char *propData; - - FSXCharInfo *extents; - FSOffset *offsets; - unsigned char *glyphs; - - int maxenc,width,height; - FSXCharInfo **eindex; - unsigned char **gindex; -}; - -#else - -typedef struct _FSXCharInfo { - short left; - short right; - short width; - short ascent; - short descent; - //unsigned short attributes; -} FSXCharInfo; - -typedef struct _FSXFontInfoHeader { - //int flags; - //FSRange char_range; - //unsigned draw_direction; - //FSChar2b default_char; - FSXCharInfo min_bounds; - FSXCharInfo max_bounds; - short font_ascent; - short font_descent; -} FSXFontInfoHeader; - -struct fs_font { - FSXFontInfoHeader fontHeader; - //unsigned char *propData; - FSXCharInfo *extents; - unsigned char *glyphs; - int maxenc,width,height; - FSXCharInfo **eindex; - unsigned char **gindex; -}; - -#endif - -/* ------------------------------------------------------------------ */ - -extern unsigned int fs_bpp, fs_black, fs_white; -void (*fs_setpixel)(void *ptr, unsigned int color); - -int fs_init_fb(int white8); -void fs_render_fb(unsigned char *ptr, int pitch, - FSXCharInfo *charInfo, unsigned char *data); -int fs_puts(struct fs_font *f, unsigned int x, unsigned int y, - unsigned char *str); -int fs_textwidth(struct fs_font *f, unsigned char *str); -void fs_render_tty(FSXCharInfo *charInfo, unsigned char *data); - -#ifndef X_DISPLAY_MISSING -int fs_connect(char *servername); -struct fs_font* fs_open(char *pattern); -#endif -struct fs_font* fs_consolefont(char **filename); -void fs_free(struct fs_font *f); |