1 /*
2 * text rendering for the framebuffer console
3 * pick fonts from X11 font server or
4 * use linux consolefont psf files.
5 * (c) 2001 Gerd Knorr <kraxel@bytesex.org>
6 */
7 #include "config.h"
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <linux/fb.h>
15
16 #include "fbtools.h"
17 #include "fs.h"
18
19 /* ------------------------------------------------------------------ */
20
21 #define BIT_ORDER BitmapFormatBitOrderMSB
22 #ifdef BYTE_ORDER
23 #undef BYTE_ORDER
24 #endif
25 #define BYTE_ORDER BitmapFormatByteOrderMSB
26 #define SCANLINE_UNIT BitmapFormatScanlineUnit8
27 #define SCANLINE_PAD BitmapFormatScanlinePad8
28 #define EXTENTS BitmapFormatImageRectMin
29
30 #define SCANLINE_PAD_BYTES 1
31 #define GLWIDTHBYTESPADDED(bits, nBytes) \
32 ((nBytes) == 1 ? (((bits) + 7) >> 3) /* pad to 1 byte */\
33 :(nBytes) == 2 ? ((((bits) + 15) >> 3) & ~1) /* pad to 2 bytes */\
34 :(nBytes) == 4 ? ((((bits) + 31) >> 3) & ~3) /* pad to 4 bytes */\
35 :(nBytes) == 8 ? ((((bits) + 63) >> 3) & ~7) /* pad to 8 bytes */\
36 : 0)
37
38 static const unsigned fs_masktab[] = {
39 (1 << 7), (1 << 6), (1 << 5), (1 << 4),
40 (1 << 3), (1 << 2), (1 << 1), (1 << 0),
41 };
42
43 /* ------------------------------------------------------------------ */
44
45 #ifndef X_DISPLAY_MISSING
46 static FSServer *svr;
47 #endif
48 static unsigned int bpp,black,white;
49
50 static void (*setpixel)(void *ptr, unsigned int color);
51
52 static void setpixel1(void *ptr, unsigned int color)
53 {
54 unsigned char *p = ptr;
55 *p = color;
56 }
57 static void setpixel2(void *ptr, unsigned int color)
58 {
59 unsigned short *p = ptr;
60 *p = color;
61 }
62 static void setpixel3(void *ptr, unsigned int color)
63 {
64 unsigned char *p = ptr;
65 *(p++) = (color >> 16) & 0xff;
66 *(p++) = (color >> 8) & 0xff;
67 *(p++) = color & 0xff;
68 }
69 static void setpixel4(void *ptr, unsigned int color)
70 {
71 unsigned long *p = ptr;
72 *p = color;
73 }
74
75 int fs_init_fb(int white8)
76 {
77 switch (fb_var.bits_per_pixel) {
78 case 8:
79 white = white8; black = 0; bpp = 1;
80 setpixel = setpixel1;
81 break;
82 case 15:
83 case 16:
84 if (fb_var.green.length == 6)
85 white = 0xffff;
86 else
87 white = 0x7fff;
88 black = 0; bpp = 2;
89 setpixel = setpixel2;
90 break;
91 case 24:
92 white = 0xffffff; black = 0; bpp = fb_var.bits_per_pixel/8;
93 setpixel = setpixel3;
94 break;
95 case 32:
96 white = 0xffffff; black = 0; bpp = fb_var.bits_per_pixel/8;
97 setpixel = setpixel4;
98 break;
99 default:
100 fprintf(stderr, "Oops: %i bit/pixel ???\n",
101 fb_var.bits_per_pixel);
102 return -1;
103 }
104 return 0;
105 }
106
107 void fs_render_fb(unsigned char *ptr, int pitch,
108 FSXCharInfo *charInfo, unsigned char *data)
109 {
110 int row,bit,bpr,x;
111
112 bpr = GLWIDTHBYTESPADDED((charInfo->right - charInfo->left),
113 SCANLINE_PAD_BYTES);
114 for (row = 0; row < (charInfo->ascent + charInfo->descent); row++) {
115 for (x = 0, bit = 0; bit < (charInfo->right - charInfo->left); bit++) {
116 if (data[bit>>3] & fs_masktab[bit&7])
117 setpixel(ptr+x,white);
118 x += bpp;
119 }
120 data += bpr;
121 ptr += pitch;
122 }
123 }
124
125 int fs_puts(struct fs_font *f, unsigned int x, unsigned int y,
126 unsigned char *str)
127 {
128 unsigned char *pos,*start;
129 int i,c,j,w;
130
131 pos = fb_mem+fb_mem_offset;
132 pos += fb_fix.line_length * y;
133 for (i = 0; str[i] != '\0'; i++) {
134 c = str[i];
135 if (NULL == f->eindex[c])
136 continue;
137 /* clear with bg color */
138 start = pos + x*bpp + f->fontHeader.max_bounds.descent * fb_fix.line_length;
139 w = (f->eindex[c]->width+1)*bpp;
140 for (j = 0; j < f->height; j++) {
141 memset(start,0,w);
142 start += fb_fix.line_length;
143 }
144 /* draw char */
145 start = pos + x*bpp + fb_fix.line_length * (f->height-f->eindex[c]->ascent);
146 fs_render_fb(start,fb_fix.line_length,f->eindex[c],f->gindex[c]);
147 x += f->eindex[c]->width;
148 if (x > fb_var.xres - f->width)
149 return -1;
150 }
151 return x;
152 }
153
154 int fs_textwidth(struct fs_font *f, unsigned char *str)
155 {
156 int width = 0;
157 int i,c;
158
159 for (i = 0; str[i] != '\0'; i++) {
160 c = str[i];
161 if (NULL == f->eindex[c])
162 continue;
163 width += f->eindex[c]->width;
164 }
165 return width;
166 }
167
168 void fs_render_tty(FSXCharInfo *charInfo, unsigned char *data)
169 {
170 int bpr,row,bit,on;
171
172 bpr = GLWIDTHBYTESPADDED((charInfo->right - charInfo->left),
173 SCANLINE_PAD_BYTES);
174 for (row = 0; row < (charInfo->ascent + charInfo->descent); row++) {
175 fprintf(stdout,"|");
176 for (bit = 0; bit < (charInfo->right - charInfo->left); bit++) {
177 on = data[bit>>3] & fs_masktab[bit&7];
178 fprintf(stdout,"%s",on ? "##" : " ");
179 }
180 fprintf(stdout,"|\n");
181 data += bpr;
182 }
183 fprintf(stdout,"--\n");
184 }
185
186 /* ------------------------------------------------------------------ */
187
188 #ifndef X_DISPLAY_MISSING
189 /* connect to font server */
190 int fs_connect(char *servername)
191 {
192 if (NULL == servername)
193 servername = getenv("FONTSERVER");
194 if (NULL == servername)
195 servername = "unix/:7100";
196 svr = FSOpenServer(servername);
197 if (NULL == svr) {
198 if (NULL == FSServerName(servername)) {
199 fprintf(stderr, "no font server defined\n");
200 } else {
201 fprintf(stderr, "unable to open server \"%s\"\n",
202 FSServerName(servername));
203 }
204 return -1;
205 }
206 return 0;
207 }
208
209 /* load font from font server */
210 struct fs_font* fs_open(char *pattern)
211 {
212 int nnames = 1;
213 int available,high,low,encoding,bpr;
214 char **fonts;
215 unsigned char *glyph;
216 Font dummy;
217 FSBitmapFormat format;
218 FSXCharInfo *charInfo;
219 struct fs_font *f = NULL;
220
221 if (NULL == svr) {
222 fprintf(stderr,"fs: not connected\n");
223 return NULL;
224 }
225
226 fonts = FSListFonts(svr, pattern, nnames, &available);
227 if (0 == available) {
228 fprintf(stderr,"fs: font not available [%s]\n",pattern);
229 goto out;
230 }
231 fprintf(stderr,"using x11 font \"%s\"\n",fonts[0]);
232
233 f = malloc(sizeof(*f));
234 memset(f,0,sizeof(*f));
235 f->font = FSOpenBitmapFont(svr, 0, 0, fonts[0], &dummy);
236 FSFreeFontNames(fonts);
237 if (0 == f->font)
238 goto out;
239
240 FSQueryXInfo(svr,f->font,&f->fontHeader, &f->propInfo,
241 &f->propOffsets, &f->propData);
242 format = BYTE_ORDER | BIT_ORDER | SCANLINE_UNIT | SCANLINE_PAD | EXTENTS;
243 FSQueryXExtents16(svr, f->font, True, (FSChar2b *) 0, 0, &f->extents);
244 FSQueryXBitmaps16(svr, f->font, format, True, (FSChar2b *) 0, 0,
245 &f->offsets, &f->glyphs);
246
247 f->maxenc = (f->fontHeader.char_range.max_char.high+1) << 8;
248 f->width = f->fontHeader.max_bounds.right - f->fontHeader.min_bounds.left;
249 f->height = f->fontHeader.max_bounds.ascent + f->fontHeader.max_bounds.descent;
250 f->eindex = malloc(f->maxenc * sizeof(FSXCharInfo*));
251 f->gindex = malloc(f->maxenc * sizeof(unsigned char*));
252 memset(f->eindex,0,f->maxenc * sizeof(FSXCharInfo*));
253 memset(f->gindex,0,f->maxenc * sizeof(unsigned char*));
254
255 glyph = f->glyphs;
256 charInfo = f->extents;
257 for (high = f->fontHeader.char_range.min_char.high;
258 high <= f->fontHeader.char_range.max_char.high;
259 high++) {
260 for (low = f->fontHeader.char_range.min_char.low;
261 low <= f->fontHeader.char_range.max_char.low;
262 low++) {
263 bpr = GLWIDTHBYTESPADDED((charInfo->right - charInfo->left),
264 SCANLINE_PAD_BYTES);
265 encoding = (high<<8) + low;
266 #ifdef TTY
267 fprintf(stdout,"e=0x%x | w=%d l=%d r=%d | a=%d d=%d\n",
268 encoding,charInfo->width,charInfo->left,
269 charInfo->right,charInfo->ascent,charInfo->descent);
270 #endif
271 if ((charInfo->width != 0) || (charInfo->right != charInfo->left)) {
272 f->gindex[encoding] = glyph;
273 f->eindex[encoding] = charInfo;
274 #ifdef TTY
275 fs_render_tty(f->eindex[encoding],
276 f->gindex[encoding]);
277 #endif
278 }
279 glyph += (charInfo->descent + charInfo->ascent) * bpr;
280 charInfo++;
281 }
282 }
283 return f;
284
285 out:
286 if (f)
287 fs_free(f);
288 return NULL;
289 }
290 #endif
291
292 void fs_free(struct fs_font *f)
293 {
294 if (f->gindex)
295 free(f->gindex);
296 #if 0
297 if (f->extents)
298 FSFree((char *) f->extents);
299 if (f->offsets)
300 FSFree((char *) f->offsets);
301 if (f->propOffsets)
302 FSFree((char *) (f->propOffsets));
303 if (f->propData)
304 FSFree((char *) (f->propData));
305 #endif
306 #if 0 /* FIXME */
307 if (f->glyphs)
308 FSFree((char *) f->glyphs);
309 #endif
310 free(f);
311 }
312
313 /* ------------------------------------------------------------------ */
314 /* load console font file */
315
316 static char *default_font[] = {
317 /* why the heck every f*cking distribution picks another
318 location for these fonts ??? */
319 "/usr/share/consolefonts/lat1-16.psf",
320 "/usr/share/consolefonts/lat1-16.psf.gz",
321 "/usr/share/consolefonts/lat1-16.psfu.gz",
322 "/usr/share/kbd/consolefonts/lat1-16.psf",
323 "/usr/share/kbd/consolefonts/lat1-16.psf.gz",
324 "/usr/share/kbd/consolefonts/lat1-16.psfu.gz",
325 "/usr/lib/kbd/consolefonts/lat1-16.psf",
326 "/usr/lib/kbd/consolefonts/lat1-16.psf.gz",
327 "/usr/lib/kbd/consolefonts/lat1-16.psfu.gz",
328 "/lib/kbd/consolefonts/lat1-16.psf",
329 "/lib/kbd/consolefonts/lat1-16.psf.gz",
330 "/lib/kbd/consolefonts/lat1-16.psfu.gz",
331 NULL
332 };
333
334 struct fs_font* fs_consolefont(char **filename)
335 {
336 int i;
337 char *h,command[256];
338 struct fs_font *f = NULL;
339 FILE *fp;
340
341 if (NULL == filename)
342 filename = default_font;
343
344 for(i = 0; filename[i] != NULL; i++) {
345 if (-1 == access(filename[i],R_OK))
346 continue;
347 break;
348 }
349 if (NULL == filename[i]) {
350 fprintf(stderr,"can't find console font file\n");
351 return NULL;
352 }
353
354 h = filename[i]+strlen(filename[i])-3;
355 if (0 == strcmp(h,".gz")) {
356 sprintf(command,"zcat %s",filename[i]);
357 fp = popen(command,"r");
358 } else {
359 fp = fopen(filename[i], "r");
360 }
361 if (NULL == fp) {
362 fprintf(stderr,"can't open %s: %s\n",filename[i],strerror(errno));
363 return NULL;
364 }
365
366 if (fgetc(fp) != 0x36 ||
367 fgetc(fp) != 0x04) {
368 fprintf(stderr,"can't use font %s\n",filename[i]);
369 return NULL;
370 }
371 fprintf(stderr,"using linux console font \"%s\"\n",filename[i]);
372
373 f = malloc(sizeof(*f));
374 memset(f,0,sizeof(*f));
375
376 fgetc(fp);
377 f->maxenc = 256;
378 f->width = 8;
379 f->height = fgetc(fp);
380 f->fontHeader.min_bounds.left = 0;
381 f->fontHeader.max_bounds.right = f->width;
382 f->fontHeader.max_bounds.descent = 0;
383 f->fontHeader.max_bounds.ascent = f->height;
384
385 f->glyphs = malloc(f->height * 256);
386 f->extents = malloc(sizeof(FSXCharInfo)*256);
387 fread(f->glyphs, 256, f->height, fp);
388 fclose(fp);
389
390 f->eindex = malloc(sizeof(FSXCharInfo*) * 256);
391 f->gindex = malloc(sizeof(unsigned char*) * 256);
392 for (i = 0; i < 256; i++) {
393 f->eindex[i] = f->extents +i;
394 f->gindex[i] = f->glyphs +i * f->height;
395 f->eindex[i]->left = 0;
396 f->eindex[i]->right = 7;
397 f->eindex[i]->width = 8;
398 f->eindex[i]->descent = 0;
399 f->eindex[i]->ascent = f->height;
400 }
401 return f;
402 }
403
404
405 #ifdef TESTING
406 /* ------------------------------------------------------------------ */
407 /* for testing */
408
409 int debug;
410
411 /* list fonts */
412 int fs_ls(char *pattern)
413 {
414 int nnames = 16;
415 int available,i;
416 char **fonts;
417
418 if (NULL == svr) {
419 fprintf(stderr,"fs: not connected\n");
420 return -1;
421 }
422
423 fonts = FSListFonts(svr, pattern, nnames, &available);
424 while (nnames <= available) {
425 nnames *= 2;
426 FSFreeFontNames(fonts);
427 fonts = FSListFonts(svr, pattern, nnames, &available);
428 }
429 for (i = 0; i < available; i++) {
430 fprintf(stderr,"%s\n",fonts[i]);
431 }
432 FSFreeFontNames(fonts);
433 return 0;
434 }
435
436 void dump_charset(struct fs_font *f)
437 {
438 unsigned char *pos;
439 int c,x,y;
440
441 x = 0, y = 0;
442 for (c = 0; c < f->maxenc; c++) {
443 if (NULL == f->eindex[c])
444 continue;
445 pos = fb_mem+fb_mem_offset;
446 pos += fb_fix.line_length * (y+f->height-f->eindex[c]->ascent);
447 pos += x*bpp;
448 fs_render_fb(pos,fb_fix.line_length,f->eindex[c],f->gindex[c]);
449 x += f->eindex[c]->right-f->eindex[c]->left+1;
450 if (x > fb_var.xres - f->width) {
451 x = 0;
452 y += f->height+1;
453 }
454 if (y > fb_var.yres - f->height)
455 break;
456 }
457 }
458
459 int main(int argc, char *argv[])
460 {
461 struct fs_font *f = NULL;
462 unsigned char dummy[42];
463 int fd;
464
465 if (argc < 2) {
466 fprintf(stderr,"missing arg\n");
467 exit(1);
468 }
469
470 /* try font server */
471 if (-1 != fs_connect(NULL)) {
472 fs_ls(argv[1]);
473 f = fs_open(argv[1]);
474 if (NULL == f)
475 fprintf(stderr,"no such font\n");
476 }
477
478 /* try console font */
479 if (NULL == f)
480 f = fs_consolefont(NULL);
481 if (NULL == f)
482 exit(1);
483
484 #ifdef TTY
485 exit(1);
486 #endif
487
488 fd = fb_init(NULL, NULL, 0);
489 fb_cleanup_fork();
490 fb_switch_init();
491 fs_init_fb();
492
493 if (argc < 3) {
494 dump_charset(f);
495 } else {
496 fs_puts(f,0,0,argv[2]);
497 }
498 fgets(dummy,42,stdin);
499
500 return 0;
501 }
502 #endif
503
|
This page was automatically generated by the
LXR engine.
|