Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


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

1 niro 658 /* 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     }