Magellan Linux

Contents of /trunk/linterm_tools/fw_builder/bootsplash/ttf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 658 - (show annotations) (download)
Mon Jan 14 16:57:24 2008 UTC (16 years, 3 months ago) by niro
File MIME type: text/plain
File size: 17482 byte(s)
initial import

1 /* render true type fonts to fb0
2 *
3 * (w) by stepan@suse.de, code reused from SDL_ttf
4 *
5 */
6
7 #include <math.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <assert.h>
12
13 #include <freetype/freetype.h>
14 #include <freetype/ftoutln.h>
15 #include <freetype/ttnameid.h>
16
17 #include "ttf.h"
18
19 #define DEFAULT_PTSIZE 18
20
21
22 /* FIXME: Right now we assume the gray-scale renderer Freetype is using
23 * supports 256 shades of gray, but we should instead key off of num_grays
24 * in the result FT_Bitmap after the FT_Render_Glyph() call. */
25 #define NUM_GRAYS 256
26
27
28 extern unsigned int fbbytes, fbx, fby, fblinelen, alpha;
29 extern unsigned char *framebuffer;
30
31 extern unsigned int fbypos, fbxpos;
32
33 unsigned char *TTF_RenderUNICODE_Shaded(TTF_Font * font,
34 const unsigned short *text,
35 unsigned int fg, unsigned int bg);
36
37 /* Cached glyph information */
38 typedef struct cached_glyph {
39 int stored;
40 FT_UInt index;
41 FT_Bitmap bitmap;
42 FT_Bitmap pixmap;
43 int minx;
44 int maxx;
45 int miny;
46 int maxy;
47 int yoffset;
48 int advance;
49 unsigned short cached;
50 } c_glyph;
51
52 struct _TTF_Font {
53 /* Freetype2 maintains all sorts of useful info itself */
54 FT_Face face;
55
56 /* We'll cache these ourselves */
57 int height;
58 int ascent;
59 int descent;
60 int lineskip;
61
62 /* The font style */
63 int style;
64
65 /* Extra width in glyph bounds for text styles */
66 int glyph_overhang;
67 float glyph_italics;
68
69 /* Information in the font for underlining */
70 int underline_offset;
71 int underline_height;
72
73 /* Cache for style-transformed glyphs */
74 c_glyph *current;
75 c_glyph cache[256];
76 c_glyph scratch;
77 };
78
79 static void Flush_Glyph(c_glyph * glyph);
80
81 static void Flush_Cache(TTF_Font * font)
82 {
83 int i;
84 int size = sizeof(font->cache) / sizeof(font->cache[0]);
85
86 for (i = 0; i < size; ++i) {
87 if (font->cache[i].cached) {
88 Flush_Glyph(&font->cache[i]);
89 }
90
91 }
92 if (font->scratch.cached) {
93 Flush_Glyph(&font->scratch);
94 }
95
96 }
97
98
99 /* character conversion */
100
101 /* Macro to convert a character to a Unicode value -- assume already Unicode */
102 #define UNICODE(c) c
103
104
105
106 static unsigned short *ASCII_to_UNICODE(unsigned short *unicode,
107 const char *text, int len)
108 {
109 int i;
110
111 for (i = 0; i < len; ++i) {
112 unicode[i] = ((const unsigned char *) text)[i];
113 }
114 unicode[i] = 0;
115
116 return unicode;
117 }
118
119 #if 0
120 static unsigned short *UTF8_to_UNICODE(unsigned short *unicode,
121 const char *utf8, int len)
122 {
123 int i, j;
124 unsigned short ch;
125
126 for (i = 0, j = 0; i < len; ++i, ++j) {
127 ch = ((const unsigned char *) utf8)[i];
128 if (ch >= 0xF0) {
129 ch = (unsigned short) (utf8[i] & 0x07) << 18;
130 ch |= (unsigned short) (utf8[++i] & 0x3F) << 12;
131 ch |= (unsigned short) (utf8[++i] & 0x3F) << 6;
132 ch |= (unsigned short) (utf8[++i] & 0x3F);
133 } else if (ch >= 0xE0) {
134 ch = (unsigned short) (utf8[i] & 0x3F) << 12;
135 ch |= (unsigned short) (utf8[++i] & 0x3F) << 6;
136 ch |= (unsigned short) (utf8[++i] & 0x3F);
137 } else if (ch >= 0xC0) {
138 ch = (unsigned short) (utf8[i] & 0x3F) << 6;
139 ch |= (unsigned short) (utf8[++i] & 0x3F);
140 }
141 unicode[j] = ch;
142 }
143 unicode[j] = 0;
144
145 return unicode;
146 }
147 #endif
148
149 /* TTF stuff */
150
151 static FT_Library library;
152 static int TTF_initialized = 0;
153
154 int TTF_Init(void)
155 {
156 int status;
157 FT_Error error;
158
159 status = 0;
160 error = FT_Init_FreeType(&library);
161 if (error) {
162 fprintf(stderr, "Couldn't init FreeType engine %d\n",
163 error);
164 status = -1;
165 } else {
166 TTF_initialized = 1;
167 }
168 return status;
169 }
170
171 void TTF_Quit(void)
172 {
173 if (TTF_initialized) {
174 FT_Done_FreeType(library);
175 }
176 TTF_initialized = 0;
177 }
178
179 #if 0
180 SDL_Surface *TTF_RenderText_Solid(TTF_Font * font,
181 const char *text, SDL_Color fg)
182 {
183 SDL_Surface *textbuf;
184 Uint16 *unicode_text;
185 int unicode_len;
186
187 /* Copy the Latin-1 text to a UNICODE text buffer */
188 unicode_len = strlen(text);
189 unicode_text =
190 (Uint16 *) malloc((unicode_len + 1) * (sizeof *unicode_text));
191 if (unicode_text == NULL) {
192 TTF_SetError("Out of memory");
193 return (NULL);
194 }
195 ASCII_to_UNICODE(unicode_text, text, unicode_len);
196
197 RenderUnicode(font, unicode_text, fg);
198
199 /* Render the new text */
200 textbuf = TTF_RenderUNICODE_Solid(font, unicode_text, fg);
201
202 /* Free the text buffer and return */
203 free(unicode_text);
204 return (textbuf);
205 }
206 #endif
207
208 unsigned char *TTF_RenderText_Shaded(TTF_Font * font, const char *text,
209 unsigned int fg, unsigned int bg)
210 {
211 unsigned char *textbuf;
212 unsigned short *unicode_text;
213 int unicode_len;
214
215 /* Copy the Latin-1 text to a UNICODE text buffer */
216 unicode_len = strlen(text);
217 unicode_text =
218 (unsigned short *) malloc((unicode_len + 1) *
219 (sizeof *unicode_text));
220 if (unicode_text == NULL) {
221 printf("Out of memory\n");
222 return (NULL);
223 }
224 ASCII_to_UNICODE(unicode_text, text, unicode_len);
225
226 /* Render the new text */
227 textbuf = TTF_RenderUNICODE_Shaded(font, unicode_text, fg, bg);
228
229 /* Free the text buffer and return */
230 free(unicode_text);
231 return (textbuf);
232 }
233
234
235
236 void TTF_CloseFont(TTF_Font * font)
237 {
238 Flush_Cache(font);
239 FT_Done_Face(font->face);
240 free(font);
241 }
242
243 void TTF_SetFontStyle(TTF_Font * font, int style)
244 {
245 font->style = style;
246 Flush_Cache(font);
247 }
248
249
250
251 TTF_Font *TTF_OpenFontIndex(const char *file, int ptsize, long index)
252 {
253 TTF_Font *font;
254 FT_Error error;
255 FT_Face face;
256 FT_Fixed scale;
257
258 extern int strict_font;
259
260 font = (TTF_Font *) malloc(sizeof *font);
261 if (font == NULL) {
262 fprintf(stderr, "Out of memory\n");
263 return NULL;
264 }
265 memset(font, 0, sizeof(*font));
266
267 /* Open the font and create ancillary data */
268 error = FT_New_Face(library, file, 0, &font->face);
269
270 if (error && !strict_font)
271 error =
272 FT_New_Memory_Face(library,
273 (const FT_Byte *) luxisri_ttf,
274 LUXISRI_SIZE, 0, &font->face);
275
276 if (error) {
277 printf("Couldn't load font file\n");
278 free(font);
279 return NULL;
280 }
281
282 if (index != 0) {
283 if (font->face->num_faces > index) {
284 FT_Done_Face(font->face);
285 error =
286 FT_New_Face(library, file, index, &font->face);
287 if (error) {
288 printf("Couldn't get font face\n");
289 free(font);
290 return NULL;
291 }
292 } else {
293 fprintf(stderr, "No such font face\n");
294 free(font);
295 return NULL;
296 }
297 }
298 face = font->face;
299
300 /* Make sure that our font face is scalable (global metrics) */
301 if (!FT_IS_SCALABLE(face)) {
302 fprintf(stderr, "Font face is not scalable\n");
303 TTF_CloseFont(font);
304 return NULL;
305 }
306 /* Set the character size and use default DPI (72) */
307 error = FT_Set_Char_Size(font->face, 0, ptsize * 64, 0, 0);
308 if (error) {
309 fprintf(stderr, "Couldn't set font size\n");
310 TTF_CloseFont(font);
311 return NULL;
312 }
313
314 /* Get the scalable font metrics for this font */
315 scale = face->size->metrics.y_scale;
316 font->ascent = FT_CEIL(FT_MulFix(face->bbox.yMax, scale));
317 font->descent = FT_CEIL(FT_MulFix(face->bbox.yMin, scale));
318 font->height = font->ascent - font->descent + /* baseline */ 1;
319 font->lineskip = FT_CEIL(FT_MulFix(face->height, scale));
320 font->underline_offset =
321 FT_FLOOR(FT_MulFix(face->underline_position, scale));
322 font->underline_height =
323 FT_FLOOR(FT_MulFix(face->underline_thickness, scale));
324 if (font->underline_height < 1) {
325 font->underline_height = 1;
326 }
327 #ifdef DEBUG_FONTS
328 printf("Font metrics:\n");
329 printf("\tascent = %d, descent = %d\n",
330 font->ascent, font->descent);
331 printf("\theight = %d, lineskip = %d\n",
332 font->height, font->lineskip);
333 printf("\tunderline_offset = %d, underline_height = %d\n",
334 font->underline_offset, font->underline_height);
335 #endif
336
337 /* Set the default font style */
338 font->style = TTF_STYLE_NORMAL;
339 font->glyph_overhang = face->size->metrics.y_ppem / 10;
340 /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */
341 font->glyph_italics = 0.207f;
342 font->glyph_italics *= font->height;
343
344 return font;
345 }
346
347
348
349 TTF_Font *TTF_OpenFont(const char *file, int ptsize)
350 {
351 return TTF_OpenFontIndex(file, ptsize, 0);
352 }
353
354
355
356 static void Flush_Glyph(c_glyph * glyph)
357 {
358 glyph->stored = 0;
359 glyph->index = 0;
360 if (glyph->bitmap.buffer) {
361 free(glyph->bitmap.buffer);
362 glyph->bitmap.buffer = 0;
363 }
364 if (glyph->pixmap.buffer) {
365 free(glyph->pixmap.buffer);
366 glyph->pixmap.buffer = 0;
367 }
368 glyph->cached = 0;
369 }
370
371 static FT_Error Load_Glyph(TTF_Font * font, unsigned short ch,
372 c_glyph * cached, int want)
373 {
374 FT_Face face;
375 FT_Error error;
376 FT_GlyphSlot glyph;
377 FT_Glyph_Metrics *metrics;
378 FT_Outline *outline;
379
380 assert(font);
381 assert(font->face);
382
383 face = font->face;
384
385 /* Load the glyph */
386 if (!cached->index) {
387 cached->index = FT_Get_Char_Index(face, ch);
388 }
389 error = FT_Load_Glyph(face, cached->index, FT_LOAD_DEFAULT);
390 if (error) {
391 return error;
392 }
393 /* Get our glyph shortcuts */
394 glyph = face->glyph;
395 metrics = &glyph->metrics;
396 outline = &glyph->outline;
397
398 /* Get the glyph metrics if desired */
399 if ((want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS)) {
400 /* Get the bounding box */
401 cached->minx = FT_FLOOR(metrics->horiBearingX);
402 cached->maxx = cached->minx + FT_CEIL(metrics->width);
403 cached->maxy = FT_FLOOR(metrics->horiBearingY);
404 cached->miny = cached->maxy - FT_CEIL(metrics->height);
405 cached->yoffset = font->ascent - cached->maxy;
406 cached->advance = FT_CEIL(metrics->horiAdvance);
407
408 /* Adjust for bold and italic text */
409 if (font->style & TTF_STYLE_BOLD) {
410 cached->maxx += font->glyph_overhang;
411 }
412 if (font->style & TTF_STYLE_ITALIC) {
413 cached->maxx += (int) ceil(font->glyph_italics);
414 }
415 cached->stored |= CACHED_METRICS;
416 }
417
418 if (((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP))
419 || ((want & CACHED_PIXMAP)
420 && !(cached->stored & CACHED_PIXMAP))) {
421 int mono = (want & CACHED_BITMAP);
422 int i;
423 FT_Bitmap *src;
424 FT_Bitmap *dst;
425
426 /* Handle the italic style */
427 if (font->style & TTF_STYLE_ITALIC) {
428 FT_Matrix shear;
429
430 shear.xx = 1 << 16;
431 shear.xy = (int) (font->glyph_italics * (1 << 16))
432 / font->height;
433 shear.yx = 0;
434 shear.yy = 1 << 16;
435
436 FT_Outline_Transform(outline, &shear);
437 }
438
439 /* Render the glyph */
440 if (mono) {
441 error =
442 FT_Render_Glyph(glyph, ft_render_mode_mono);
443 } else {
444 error =
445 FT_Render_Glyph(glyph, ft_render_mode_normal);
446 }
447 if (error) {
448 return error;
449 }
450
451 /* Copy over information to cache */
452 src = &glyph->bitmap;
453 if (mono) {
454 dst = &cached->bitmap;
455 } else {
456 dst = &cached->pixmap;
457 }
458 memcpy(dst, src, sizeof(*dst));
459 if (mono) {
460 dst->pitch *= 8;
461 }
462
463 /* Adjust for bold and italic text */
464 if (font->style & TTF_STYLE_BOLD) {
465 int bump = font->glyph_overhang;
466 dst->pitch += bump;
467 dst->width += bump;
468 }
469 if (font->style & TTF_STYLE_ITALIC) {
470 int bump = (int) ceil(font->glyph_italics);
471 dst->pitch += bump;
472 dst->width += bump;
473 }
474
475 if (dst->rows != 0) {
476 dst->buffer = malloc(dst->pitch * dst->rows);
477 if (!dst->buffer) {
478 return FT_Err_Out_Of_Memory;
479 }
480 memset(dst->buffer, 0, dst->pitch * dst->rows);
481
482 for (i = 0; i < src->rows; i++) {
483 int soffset = i * src->pitch;
484 int doffset = i * dst->pitch;
485 if (mono) {
486 unsigned char *srcp = src->buffer +
487 soffset;
488 unsigned char *dstp = dst->buffer +
489 doffset;
490 int j;
491 for (j = 0; j < src->width; j += 8) {
492 unsigned char ch = *srcp++;
493 *dstp++ = (ch & 0x80) >> 7;
494 ch <<= 1;
495 *dstp++ = (ch & 0x80) >> 7;
496 ch <<= 1;
497 *dstp++ = (ch & 0x80) >> 7;
498 ch <<= 1;
499 *dstp++ = (ch & 0x80) >> 7;
500 ch <<= 1;
501 *dstp++ = (ch & 0x80) >> 7;
502 ch <<= 1;
503 *dstp++ = (ch & 0x80) >> 7;
504 ch <<= 1;
505 *dstp++ = (ch & 0x80) >> 7;
506 ch <<= 1;
507 *dstp++ = (ch & 0x80) >> 7;
508 }
509 } else {
510 memcpy(dst->buffer + doffset,
511 src->buffer + soffset,
512 src->pitch);
513 }
514 }
515 }
516
517 /* Handle the bold style */
518 if (font->style & TTF_STYLE_BOLD) {
519 int row;
520 int col;
521 int offset;
522 int pixel;
523 unsigned char *pixmap;
524
525 /* The pixmap is a little hard, we have to add and clamp */
526 for (row = dst->rows - 1; row >= 0; --row) {
527 pixmap =
528 (unsigned char *) dst->buffer +
529 row * dst->pitch;
530 for (offset = 1;
531 offset <= font->glyph_overhang;
532 ++offset) {
533 for (col = dst->width - 1; col > 0;
534 --col) {
535 pixel =
536 (pixmap[col] +
537 pixmap[col - 1]);
538 if (pixel > NUM_GRAYS - 1) {
539 pixel =
540 NUM_GRAYS - 1;
541 }
542 pixmap[col] =
543 (unsigned char) pixel;
544 }
545 }
546 }
547 }
548
549 /* Mark that we rendered this format */
550 if (mono) {
551 cached->stored |= CACHED_BITMAP;
552 } else {
553 cached->stored |= CACHED_PIXMAP;
554 }
555 }
556
557 /* We're done, mark this glyph cached */
558 cached->cached = ch;
559
560 return 0;
561 }
562
563
564
565
566
567
568
569 static FT_Error Find_Glyph(TTF_Font * font, unsigned short ch, int want)
570 {
571 int retval = 0;
572
573 if (ch < 256) {
574 font->current = &font->cache[ch];
575 } else {
576 if (font->scratch.cached != ch) {
577 Flush_Glyph(&font->scratch);
578 }
579 font->current = &font->scratch;
580 }
581 if ((font->current->stored & want) != want) {
582 retval = Load_Glyph(font, ch, font->current, want);
583 }
584 return retval;
585 }
586
587 int TTF_SizeUNICODE(TTF_Font * font, const unsigned short *text, int *w,
588 int *h)
589 {
590 int status;
591 const unsigned short *ch;
592 int x, z;
593 int minx, maxx;
594 int miny, maxy;
595 c_glyph *glyph;
596 FT_Error error;
597
598 /* Initialize everything to 0 */
599 if (!TTF_initialized) {
600 return -1;
601 }
602 status = 0;
603 minx = maxx = 0;
604 miny = maxy = 0;
605
606 /* Load each character and sum it's bounding box */
607 x = 0;
608 for (ch = text; *ch; ++ch) {
609 error = Find_Glyph(font, *ch, CACHED_METRICS);
610 if (error) {
611 return -1;
612 }
613 glyph = font->current;
614
615 z = x + glyph->minx;
616 if (minx > z) {
617 minx = z;
618 }
619 if (font->style & TTF_STYLE_BOLD) {
620 x += font->glyph_overhang;
621 }
622 if (glyph->advance > glyph->maxx) {
623 z = x + glyph->advance;
624 } else {
625 z = x + glyph->maxx;
626 }
627 if (maxx < z) {
628 maxx = z;
629 }
630 x += glyph->advance;
631
632 if (glyph->miny < miny) {
633 miny = glyph->miny;
634 }
635 if (glyph->maxy > maxy) {
636 maxy = glyph->maxy;
637 }
638 }
639
640 /* Fill the bounds rectangle */
641 if (w) {
642 *w = (maxx - minx);
643 }
644 if (h)
645 *h = font->height;
646
647 return status;
648 }
649
650
651 unsigned char *TTF_RenderUNICODE_Shaded(TTF_Font * font,
652 const unsigned short *text,
653 unsigned int fg, unsigned int bg)
654 {
655 int xstart;
656 int width;
657 int height;
658 unsigned char *textbuf;
659 int rdiff;
660 int gdiff;
661 int bdiff;
662 unsigned short val, bgc;
663 const unsigned short *ch;
664 unsigned char *src;
665 unsigned char *dst;
666 int row, col;
667 c_glyph *glyph;
668 FT_Error error;
669
670 /* Get the dimensions of the text surface */
671 if ((TTF_SizeUNICODE(font, text, &width, NULL) < 0) || !width) {
672 fprintf(stderr, "Text has zero width\n");
673 return NULL;
674 }
675 height = font->height;
676
677 /* Create the target surface */
678 textbuf = malloc(width * height * fbbytes);
679
680 if (textbuf == NULL) {
681 return NULL;
682 }
683
684 /* Load and render each character */
685 xstart = 0;
686 for (ch = text; *ch; ++ch) {
687 FT_Bitmap *current;
688
689 error =
690 Find_Glyph(font, *ch, CACHED_METRICS | CACHED_PIXMAP);
691 if (error) {
692 free(textbuf);
693 return NULL;
694 }
695 glyph = font->current;
696
697 current = &glyph->pixmap;
698 for (row = 0; row < current->rows; ++row) {
699 dst = (unsigned char *) framebuffer +
700 (fbypos + row + glyph->yoffset) * fblinelen +
701 (xstart + glyph->minx + fbxpos) * fbbytes;
702 src = current->buffer + row * current->pitch;
703 for (col = current->width; col > 0; --col) {
704 val = *src++;
705 bgc = *(unsigned short *) dst;
706
707 /* get color parts from real color */
708 rdiff = (fg >> 16);
709 gdiff = ((fg >> 8) & 0xff);
710 bdiff = (fg & 0xff);
711
712 val = alpha * val / 100;
713 /* dim color down to current pixel value */
714 rdiff = rdiff * val / 0xff;
715 gdiff = gdiff * val / 0xff;
716 bdiff = bdiff * val / 0xff;
717
718 #if 1
719 /* do alpha transparency */
720 //rdiff=(rdiff*alpha/100);
721 rdiff +=
722 ((bgc) >> 8 & 0xf8) * (0xff -
723 val) / 0xff;
724
725 //gdiff=(gdiff*alpha/100);
726 gdiff +=
727 ((bgc >> 3) & 0xfc) * (0xff -
728 val) / 0xff;
729
730 //bdiff=(bdiff*alpha/100);
731 bdiff +=
732 ((bgc << 3) & 0xf8) * (0xff -
733 val) / 0xff;
734 #endif
735
736 val =
737 ((rdiff & 0xf8) << 8) | ((gdiff & 0xfc)
738 << 3) | (bdiff
739 >>
740 3);
741 //*dst++ = (val >>8);
742 *dst++ = val & 0xff;
743 *dst++ = (val >> 8);
744 }
745 //printf("\n");
746 }
747
748 xstart += glyph->advance;
749 if (font->style & TTF_STYLE_BOLD) {
750 xstart += font->glyph_overhang;
751 }
752 }
753
754 /* Handle the underline style */
755 if (font->style & TTF_STYLE_UNDERLINE) {
756 row = font->ascent - font->underline_offset - 1;
757 if (row >= fby) {
758 row = (height - 1) - font->underline_height;
759 }
760 dst = (unsigned char *) textbuf + row * width * fbbytes;
761 for (row = font->underline_height; row > 0; --row) {
762 memset(dst, NUM_GRAYS - 1, width);
763 dst += width * fbbytes;
764 }
765 }
766 return textbuf;
767 }
768
769
770 int rendertext(char *text, char *fontname, unsigned int ptsize,
771 unsigned int forecol)
772 {
773 TTF_Font *font;
774 int renderstyle = 0;
775
776 enum {
777 RENDER_LATIN1,
778 RENDER_UTF8,
779 RENDER_UNICODE
780 } rendertype;
781
782
783 /* Initialize the TTF library */
784 if (TTF_Init() < 0) {
785 fprintf(stderr, "Couldn't initialize TTF.\n");
786 return (2);
787 }
788 atexit(TTF_Quit);
789
790 /* Open the font file with the requested point size */
791 font = TTF_OpenFont(fontname, ptsize);
792 if (font == NULL) {
793 fprintf(stderr, "Couldn't load %d pt font from %s\n",
794 ptsize, fontname);
795 return (2);
796 }
797
798 renderstyle = TTF_STYLE_NORMAL;
799 rendertype = RENDER_LATIN1;
800
801 TTF_SetFontStyle(font, renderstyle);
802 text = TTF_RenderText_Shaded(font, text, forecol, 0);
803
804 return 0;
805 }