1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stddef.h>
4 #include <string.h>
5 #include <math.h>
6 #include <wchar.h>
7 #include <inttypes.h>
8 #include <sys/ioctl.h>
9 #include <linux/fb.h>
10
11 #include <fontconfig/fontconfig.h>
12 #include <fontconfig/fcfreetype.h>
13
14 #include "vt.h"
15 #include "fbtools.h"
16 #include "dither.h"
17 #include "fb-gui.h"
18
19 static int ys = 3;
20 static int xs = 10;
21
22 /* ---------------------------------------------------------------------- */
23 /* shadow framebuffer -- internals */
24
25 static int32_t s_lut_transp[256], s_lut_red[256], s_lut_green[256], s_lut_blue[256];
26
27 static unsigned char **shadow;
28 static unsigned int *sdirty,swidth,sheight;
29
shadow_lut_init_one(int32_t * lut,int bits,int shift)30 static void shadow_lut_init_one(int32_t *lut, int bits, int shift)
31 {
32 int i;
33
34 if (bits > 8)
35 for (i = 0; i < 256; i++)
36 lut[i] = (i << (bits + shift - 8));
37 else
38 for (i = 0; i < 256; i++)
39 lut[i] = (i >> (8 - bits)) << shift;
40 }
41
shadow_lut_init(gfxstate * gfx)42 static void shadow_lut_init(gfxstate *gfx)
43 {
44 shadow_lut_init_one(s_lut_transp, gfx->tlen, gfx->toff);
45 shadow_lut_init_one(s_lut_red, gfx->rlen, gfx->roff);
46 shadow_lut_init_one(s_lut_green, gfx->glen, gfx->goff);
47 shadow_lut_init_one(s_lut_blue, gfx->blen, gfx->boff);
48 }
49
shadow_render_line(gfxstate * gfx,int line,unsigned char * dest,char unsigned * buffer)50 static void shadow_render_line(gfxstate *gfx, int line,
51 unsigned char *dest, char unsigned *buffer)
52 {
53 uint8_t *ptr = (void*)dest;
54 uint16_t *ptr2 = (void*)dest;
55 uint32_t *ptr4 = (void*)dest;
56 int x;
57
58 switch (gfx->bits_per_pixel) {
59 case 8:
60 dither_line(buffer, ptr, line, swidth);
61 break;
62 case 15:
63 case 16:
64 for (x = 0; x < swidth; x++) {
65 ptr2[x] = s_lut_red[buffer[x*3]] |
66 s_lut_green[buffer[x*3+1]] |
67 s_lut_blue[buffer[x*3+2]];
68 }
69 break;
70 case 24:
71 for (x = 0; x < swidth; x++) {
72 ptr[3*x+2] = buffer[3*x+0];
73 ptr[3*x+1] = buffer[3*x+1];
74 ptr[3*x+0] = buffer[3*x+2];
75 }
76 break;
77 case 32:
78 for (x = 0; x < swidth; x++) {
79 ptr4[x] = s_lut_transp[255] |
80 s_lut_red[buffer[x*3]] |
81 s_lut_green[buffer[x*3+1]] |
82 s_lut_blue[buffer[x*3+2]];
83 }
84 break;
85 }
86 }
87
88 /* ---------------------------------------------------------------------- */
89 /* shadow framebuffer -- management interface */
90
shadow_render(gfxstate * gfx)91 void shadow_render(gfxstate *gfx)
92 {
93 unsigned int offset = 0;
94 int i;
95
96 if (!console_visible)
97 return;
98 for (i = 0; i < sheight; i++, offset += gfx->stride) {
99 if (0 == sdirty[i])
100 continue;
101 shadow_render_line(gfx, i, gfx->mem + offset, shadow[i]);
102 sdirty[i] = 0;
103 }
104 if (gfx->flush_display)
105 gfx->flush_display(false);
106 }
107
shadow_clear_lines(int first,int last)108 void shadow_clear_lines(int first, int last)
109 {
110 int i;
111
112 for (i = first; i <= last; i++) {
113 memset(shadow[i],0,3*swidth);
114 sdirty[i]++;
115 }
116 }
117
shadow_clear(void)118 void shadow_clear(void)
119 {
120 shadow_clear_lines(0, sheight-1);
121 }
122
shadow_set_dirty(void)123 void shadow_set_dirty(void)
124 {
125 int i;
126
127 for (i = 0; i < sheight; i++)
128 sdirty[i]++;
129 }
130
shadow_init(gfxstate * gfx)131 void shadow_init(gfxstate *gfx)
132 {
133 int i;
134
135 /* init shadow fb */
136 swidth = gfx->hdisplay;
137 sheight = gfx->vdisplay;
138 shadow = malloc(sizeof(unsigned char*) * sheight);
139 sdirty = malloc(sizeof(unsigned int) * sheight);
140 memset(sdirty,0, sizeof(unsigned int) * sheight);
141 for (i = 0; i < sheight; i++)
142 shadow[i] = malloc(swidth*3);
143 shadow_clear();
144
145 /* init rendering */
146 switch (gfx->bits_per_pixel) {
147 case 8:
148 init_dither(8, 8, 4, 2);
149 dither_line = dither_line_color;
150 break;
151 case 15:
152 case 16:
153 case 24:
154 case 32:
155 shadow_lut_init(gfx);
156 break;
157 default:
158 fprintf(stderr, "Oops: %i bit/pixel ???\n",
159 gfx->bits_per_pixel);
160 exit(1);
161 }
162 }
163
shadow_fini(void)164 void shadow_fini(void)
165 {
166 int i;
167
168 if (!shadow)
169 return;
170 for (i = 0; i < sheight; i++)
171 free(shadow[i]);
172 free(shadow);
173 free(sdirty);
174 }
175
176 /* ---------------------------------------------------------------------- */
177 /* shadow framebuffer -- drawing interface */
178
shadow_setpixel(int x,int y)179 static void shadow_setpixel(int x, int y)
180 {
181 unsigned char *dest = shadow[y] + 3*x;
182
183 if (x < 0)
184 return;
185 if (x >= swidth)
186 return;
187 if (y < 0)
188 return;
189 if (y >= sheight)
190 return;
191 *(dest++) = 255;
192 *(dest++) = 255;
193 *(dest++) = 255;
194 sdirty[y]++;
195 }
196
shadow_draw_line(int x1,int x2,int y1,int y2)197 void shadow_draw_line(int x1, int x2, int y1,int y2)
198 {
199 int x,y,h;
200 float inc;
201
202 if (x2 < x1)
203 h = x2, x2 = x1, x1 = h;
204 if (y2 < y1)
205 h = y2, y2 = y1, y1 = h;
206
207 if (x2 - x1 < y2 - y1) {
208 inc = (float)(x2-x1)/(float)(y2-y1);
209 for (y = y1; y <= y2; y++) {
210 x = x1 + inc * (y - y1);
211 shadow_setpixel(x,y);
212 }
213 } else {
214 inc = (float)(y2-y1)/(float)(x2-x1);
215 for (x = x1; x <= x2; x++) {
216 y = y1 + inc * (x - x1);
217 shadow_setpixel(x,y);
218 }
219 }
220 }
221
shadow_draw_rect(int x1,int x2,int y1,int y2)222 void shadow_draw_rect(int x1, int x2, int y1,int y2)
223 {
224 shadow_draw_line(x1, x2, y1, y1);
225 shadow_draw_line(x1, x2, y2, y2);
226 shadow_draw_line(x1, x1, y1, y2);
227 shadow_draw_line(x2, x2, y1, y2);
228 }
229
shadow_draw_rgbdata(int x,int y,int pixels,unsigned char * rgb)230 void shadow_draw_rgbdata(int x, int y, int pixels, unsigned char *rgb)
231 {
232 unsigned char *dest = shadow[y] + 3*x;
233
234 memcpy(dest,rgb,3*pixels);
235 sdirty[y]++;
236 }
237
shadow_merge_rgbdata(int x,int y,int pixels,int weight,unsigned char * rgb)238 void shadow_merge_rgbdata(int x, int y, int pixels, int weight,
239 unsigned char *rgb)
240 {
241 unsigned char *dest = shadow[y] + 3*x;
242 int i = 3*pixels;
243
244 weight = weight * 256 / 100;
245
246 while (i-- > 0)
247 *(dest++) += *(rgb++) * weight >> 8;
248 sdirty[y]++;
249 }
250
251
shadow_darkify(int x1,int x2,int y1,int y2,int percent)252 void shadow_darkify(int x1, int x2, int y1,int y2, int percent)
253 {
254 unsigned char *ptr;
255 int x,y,h;
256
257 if (x2 < x1)
258 h = x2, x2 = x1, x1 = h;
259 if (y2 < y1)
260 h = y2, y2 = y1, y1 = h;
261
262 if (x1 < 0)
263 x1 = 0;
264 if (x2 >= swidth)
265 x2 = swidth;
266
267 if (y1 < 0)
268 y1 = 0;
269 if (y2 >= sheight)
270 y2 = sheight;
271
272 percent = percent * 256 / 100;
273
274 for (y = y1; y <= y2; y++) {
275 sdirty[y]++;
276 ptr = shadow[y];
277 ptr += 3*x1;
278 x = 3*(x2-x1+1);
279 while (x-- > 0) {
280 *ptr = (*ptr * percent) >> 8;
281 ptr++;
282 }
283 }
284 }
285
shadow_reverse(int x1,int x2,int y1,int y2)286 void shadow_reverse(int x1, int x2, int y1,int y2)
287 {
288 unsigned char *ptr;
289 int x,y,h;
290
291 if (x2 < x1)
292 h = x2, x2 = x1, x1 = h;
293 if (y2 < y1)
294 h = y2, y2 = y1, y1 = h;
295
296 if (x1 < 0)
297 x1 = 0;
298 if (x2 >= swidth)
299 x2 = swidth;
300
301 if (y1 < 0)
302 y1 = 0;
303 if (y2 >= sheight)
304 y2 = sheight;
305
306 for (y = y1; y <= y2; y++) {
307 sdirty[y]++;
308 ptr = shadow[y];
309 for (x = x1; x <= x2; x++) {
310 ptr[3*x+0] = 255-ptr[3*x+0];
311 ptr[3*x+1] = 255-ptr[3*x+1];
312 ptr[3*x+2] = 255-ptr[3*x+2];
313 }
314 }
315 }
316
317 /* ---------------------------------------------------------------------- */
318 /* shadow framebuffer -- text rendering */
319
shadow_draw_glyph(FT_Bitmap * bitmap,int sx,int sy)320 static void shadow_draw_glyph(FT_Bitmap *bitmap, int sx, int sy)
321 {
322 unsigned char *src,*dst;
323 unsigned int bit;
324 int x,y;
325
326 src = bitmap->buffer;
327 for (y = 0; y < bitmap->rows; y++, src += bitmap->pitch) {
328 if (sy+y < 0)
329 continue;
330 if (sy+y >= sheight)
331 continue;
332 sdirty[sy+y]++;
333 dst = shadow[sy+y] + sx*3;
334 switch (bitmap->pixel_mode) {
335 case FT_PIXEL_MODE_MONO:
336 for (x = 0; x < bitmap->width; x++, dst += 3) {
337 if (sx+x < 0)
338 continue;
339 if (sx+x >= swidth)
340 continue;
341 bit = (1 << (7-(x&7)));
342 if (bit & (src[x >> 3])) {
343 dst[0] = 255;
344 dst[1] = 255;
345 dst[2] = 255;
346 }
347 }
348 break;
349 case FT_PIXEL_MODE_GRAY:
350 for (x = 0; x < bitmap->width; x++, dst += 3) {
351 if (sx+x < 0)
352 continue;
353 if (sx+x >= swidth)
354 continue;
355 if (src[x]) {
356 dst[0] += (255-dst[0]) * src[x] / 255;
357 dst[1] += (255-dst[1]) * src[x] / 255;
358 dst[2] += (255-dst[2]) * src[x] / 255;
359 }
360 }
361 break;
362 }
363 }
364 }
365
366 struct glyph {
367 FT_Glyph glyph;
368 int pos;
369 };
370
shadow_draw_string(FT_Face face,int x,int y,wchar_t * str,int align)371 int shadow_draw_string(FT_Face face, int x, int y, wchar_t *str, int align)
372 {
373 struct glyph *glyphs;
374 FT_UInt gi,pgi;
375 FT_Vector delta,pen;
376 FT_Glyph image;
377 FT_BitmapGlyph bit;
378 size_t len;
379 int i,ng,pos;
380 int kerning;
381
382 len = wcslen(str);
383 glyphs = malloc(sizeof(*glyphs) * len);
384 memset(glyphs,0,sizeof(*glyphs) * len);
385
386 kerning = FT_HAS_KERNING(face);
387 pgi = 0;
388
389 for (ng = 0, pos = 0, i = 0; str[i] != 0; i++) {
390 gi = FT_Get_Char_Index(face, str[i]);
391 if (kerning && pgi && gi) {
392 FT_Get_Kerning(face,pgi,gi,FT_KERNING_DEFAULT,&delta);
393 pos += delta.x;
394 }
395 glyphs[ng].pos = pos;
396 if (0 != FT_Load_Glyph(face, gi, FT_LOAD_DEFAULT))
397 continue;
398 if (0 != FT_Get_Glyph(face->glyph, &glyphs[ng].glyph))
399 continue;
400 pos += face->glyph->advance.x;
401 pgi = gi;
402 ng++;
403 }
404
405 switch(align) {
406 case -1: /* left */
407 break;
408 case 0: /* center */
409 x -= pos >> 7;
410 break;
411 case 1: /* right */
412 x -= pos >> 6;
413 break;
414 }
415 pen.x = 0;
416 pen.y = 0;
417 for (i = 0; i < ng; i++) {
418 image = glyphs[i].glyph;
419 if (0 != FT_Glyph_To_Bitmap(&image,FT_RENDER_MODE_NORMAL,&pen,0))
420 continue;
421 bit = (FT_BitmapGlyph)image;
422 shadow_draw_glyph(&bit->bitmap,
423 x + bit->left + (glyphs[i].pos >> 6),
424 y - bit->top);
425 if (image != glyphs[i].glyph)
426 FT_Done_Glyph(image);
427 }
428
429 for (i = 0; i < ng; i++)
430 FT_Done_Glyph(glyphs[i].glyph);
431 free(glyphs);
432
433 return pos >> 6;
434 }
435
shadow_draw_string_cursor(FT_Face face,int x,int y,wchar_t * str,int pos)436 void shadow_draw_string_cursor(FT_Face face, int x, int y, wchar_t *str, int pos)
437 {
438 wchar_t save;
439 int len, left, width, y1, y2;
440
441 len = wcslen(str);
442 if (pos >= len) {
443 left = shadow_draw_string(face, x, y, str, -1);
444 width = shadow_draw_string(face, x+left, y, L" ", -1);
445 } else {
446 save = str[pos];
447 str[pos] = 0;
448 left = shadow_draw_string(face, x, y, str, -1);
449 str[pos] = save;
450
451 save = str[pos+1];
452 str[pos+1] = 0;
453 width = shadow_draw_string(face, x+left, y, str+pos, -1);
454 str[pos+1] = save;
455
456 shadow_draw_string(face, x+left+width, y, str+pos+1, -1);
457 }
458
459 y2 = y - (face->size->metrics.descender >> 6) -1;
460 y1 = y2 - (face->size->metrics.height >> 6) +1;
461 shadow_reverse(left,left+width,y1,y2);
462 }
463
shadow_draw_text_box(FT_Face face,int x,int y,int percent,wchar_t * lines[],unsigned int count)464 void shadow_draw_text_box(FT_Face face, int x, int y, int percent, wchar_t *lines[], unsigned int count)
465 {
466 unsigned int i,len,max, x1, x2, y1, y2;
467
468 if (!console_visible)
469 return;
470
471 max = 0;
472 for (i = 0; i < count; i++) {
473 len = wcslen(lines[i]);
474 if (max < len)
475 max = len;
476 }
477
478 FT_Load_Glyph(face, FT_Get_Char_Index(face, 'x'), FT_LOAD_DEFAULT);
479 x1 = x;
480 x2 = x + max * (face->glyph->advance.x >> 6);
481 y1 = y;
482 y2 = y + count * (face->size->metrics.height >> 6);
483
484 x += xs; x2 += 2*xs;
485 y += ys; y2 += 2*ys;
486 y += (face->size->metrics.height >> 6);
487 y += (face->size->metrics.descender >> 6);
488
489 shadow_darkify(x1, x2, y1, y2, percent);
490 shadow_draw_rect(x1, x2, y1, y2);
491 for (i = 0; i < count; i++) {
492 shadow_draw_string(face, x, y, lines[i], -1);
493 y += (face->size->metrics.height >> 6);
494 }
495 }
496
497 /* ---------------------------------------------------------------------- */
498 /* fontconfig + freetype font rendering */
499
500 static FT_Library freetype;
501
font_init(void)502 void font_init(void)
503 {
504 int rc;
505
506 FcInit();
507 rc = FT_Init_FreeType(&freetype);
508 if (rc) {
509 fprintf(stderr,"FT_Init_FreeType() failed\n");
510 exit(1);
511 }
512 }
513
font_open(char * fcname)514 FT_Face font_open(char *fcname)
515 {
516 FcResult result = 0;
517 FT_Face face = NULL;
518 FcPattern *pattern,*match;
519 char *fontname,*h;
520 FcChar8 *filename;
521 double pixelsize;
522 int rc;
523
524 /* parse + match font name */
525 pattern = FcNameParse(fcname);
526 FcConfigSubstitute(NULL, pattern, FcMatchPattern);
527 FcDefaultSubstitute(pattern);
528 match = FcFontMatch (0, pattern, &result);
529 FcPatternDestroy(pattern);
530 if (FcResultMatch != result)
531 return NULL;
532 fontname = FcNameUnparse(match);
533 h = strchr(fontname, ':');
534 if (h)
535 *h = 0;
536
537 /* try get the face directly */
538 result = FcPatternGetFTFace(match, FC_FT_FACE, 0, &face);
539 if (FcResultMatch == result) {
540 fprintf(stderr,"using \"%s\", face=%p\n",fontname,face);
541 return face;
542 }
543
544 /* failing that use the filename */
545 result = FcPatternGetString (match, FC_FILE, 0, &filename);
546 if (FcResultMatch == result) {
547 result = FcPatternGetDouble(match, FC_PIXEL_SIZE, 0, &pixelsize);
548 if (FcResultMatch != result)
549 pixelsize = 16;
550 fprintf(stderr,"using \"%s\", pixelsize=%.2lf file=%s\n",
551 fontname,pixelsize,filename);
552 rc = FT_New_Face (freetype, filename, 0, &face);
553 if (rc)
554 return NULL;
555 FT_Set_Pixel_Sizes(face, 0, (int)pixelsize);
556 return face;
557 }
558
559 /* oops, didn't work */
560 return NULL;
561 }
562