]> git.imager.perl.org - imager.git/blob - freetyp2.c
Fixed some mlog() messages using uninitialized variables.
[imager.git] / freetyp2.c
1 /*
2 =head1 NAME
3
4 freetyp2.c - font support via the FreeType library version 2.
5
6 =head1 SYNOPSIS
7
8   if (!i_ft2_init()) { error }
9   FT2_Fonthandle *font;
10   font = i_ft2_new(name, index);
11   if (!i_ft2_setdpi(font, xdpi, ydpi)) { error }
12   if (!i_ft2_getdpi(font, &xdpi, &ydpi)) { error }
13   double matrix[6];
14   if (!i_ft2_settransform(font, matrix)) { error }
15   int bbox[6];
16   if (!i_ft2_bbox(font, cheight, cwidth, text, length, bbox)) { error }
17   i_img *im = ...;
18   i_color cl;
19   if (!i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, length, align,
20                   aa)) { error }
21   if (!i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, length,
22                 align, aa)) { error }
23   i_ft2_destroy(font);
24
25 =head1 DESCRIPTION
26
27 Implements Imager font support using the FreeType2 library.
28
29 The FreeType2 library understands several font file types, including
30 Truetype, Type1 and Windows FNT.
31
32 =over 
33
34 =cut
35 */
36
37 #include "image.h"
38 #include <stdio.h>
39 #include <ft2build.h>
40 #include FT_FREETYPE_H
41
42 static void ft2_push_message(int code);
43 static unsigned long utf8_advance(char **p, int *len);
44
45 static FT_Library library;
46
47 /*
48 =item i_ft2_init(void)
49
50 Initializes the Freetype 2 library.
51
52 Returns true on success, false on failure.
53
54 =cut
55 */
56 int
57 i_ft2_init(void) {
58   FT_Error error;
59
60   i_clear_error();
61   error = FT_Init_FreeType(&library);
62   if (error) {
63     ft2_push_message(error);
64     i_push_error(0, "Initializing Freetype2");
65     return 0;
66   }
67   return 1;
68 }
69
70 struct FT2_Fonthandle {
71   FT_Face face;
72   int xdpi, ydpi;
73   int hint;
74
75   /* used to adjust so we can align the draw point to the top-left */
76   double matrix[6];
77 };
78
79 /*
80 =item i_ft2_new(char *name, int index)
81
82 Creates a new font object, from the file given by I<name>.  I<index>
83 is the index of the font in a file with multiple fonts, where 0 is the
84 first font.
85
86 Return NULL on failure.
87
88 =cut
89 */
90
91 FT2_Fonthandle *
92 i_ft2_new(char *name, int index) {
93   FT_Error error;
94   FT2_Fonthandle *result;
95   FT_Face face;
96   double matrix[6] = { 1, 0, 0,
97                        0, 1, 0 };
98
99   i_clear_error();
100   error = FT_New_Face(library, name, index, &face);
101   if (error) {
102     ft2_push_message(error);
103     i_push_error(error, "Opening face");
104     return NULL;
105   }
106
107   result = mymalloc(sizeof(FT2_Fonthandle));
108   result->face = face;
109   result->xdpi = result->ydpi = 72;
110
111   /* by default we disable hinting on a call to i_ft2_settransform()
112      if we don't do this, then the hinting can the untransformed text
113      to be a different size to the transformed text.
114      Obviously we have it initially enabled.
115   */
116   result->hint = 1; 
117
118   /* I originally forgot this:   :/ */
119   /*i_ft2_settransform(result, matrix); */
120   result->matrix[0] = 1; result->matrix[1] = 0; result->matrix[2] = 0;
121   result->matrix[3] = 0; result->matrix[4] = 1; result->matrix[5] = 0;
122
123   return result;
124 }
125
126 /*
127 =item i_ft2_destroy(FT2_Fonthandle *handle)
128
129 Destroys a font object, which must have been the return value of
130 i_ft2_new().
131
132 =cut
133 */
134 void
135 i_ft2_destroy(FT2_Fonthandle *handle) {
136   FT_Done_Face(handle->face);
137   myfree(handle);
138 }
139
140 /*
141 =item i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi)
142
143 Sets the resolution in dots per inch at which point sizes scaled, by
144 default xdpi and ydpi are 72, so that 1 point maps to 1 pixel.
145
146 Both xdpi and ydpi should be positive.
147
148 Return true on success.
149
150 =cut
151 */
152 int
153 i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi) {
154   i_clear_error();
155   if (xdpi > 0 && ydpi > 0) {
156     handle->xdpi = xdpi;
157     handle->ydpi = ydpi;
158     return 0;
159   }
160   else {
161     i_push_error(0, "resolutions must be positive");
162     return 0;
163   }
164 }
165
166 /*
167 =item i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi)
168
169 Retrieves the current horizontal and vertical resolutions at which
170 point sizes are scaled.
171
172 =cut
173 */
174 int
175 i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi) {
176   *xdpi = handle->xdpi;
177   *ydpi = handle->ydpi;
178
179   return 1;
180 }
181
182 /*
183 =item i_ft2_settransform(FT2_FontHandle *handle, double *matrix)
184
185 Sets a transormation matrix for output.
186
187 This should be a 2 x 3 matrix like:
188
189  matrix[0]   matrix[1]   matrix[2]
190  matrix[3]   matrix[4]   matrix[5]
191
192 =cut
193 */
194 int
195 i_ft2_settransform(FT2_Fonthandle *handle, double *matrix) {
196   FT_Matrix m;
197   FT_Vector v;
198   int i;
199
200   m.xx = matrix[0] * 65536;
201   m.xy = matrix[1] * 65536;
202   v.x  = matrix[2]; /* this could be pels of 26.6 fixed - not sure */
203   m.yx = matrix[3] * 65536;
204   m.yy = matrix[4] * 65536;
205   v.y  = matrix[5]; /* see just above */
206
207   FT_Set_Transform(handle->face, &m, &v);
208
209   for (i = 0; i < 6; ++i)
210     handle->matrix[i] = matrix[i];
211   handle->hint = 0;
212
213   return 1;
214 }
215
216 /*
217 =item i_ft2_sethinting(FT2_Fonthandle *handle, int hinting)
218
219 If hinting is non-zero then glyph hinting is enabled, otherwise disabled.
220
221 i_ft2_settransform() disables hinting to prevent distortions in
222 gradual text transformations.
223
224 =cut
225 */
226 int i_ft2_sethinting(FT2_Fonthandle *handle, int hinting) {
227   handle->hint = hinting;
228   return 1;
229 }
230
231 /*
232 =item i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, int len, int *bbox)
233
234 Retrieves bounding box information for the font at the given 
235 character width and height.  This ignores the transformation matrix.
236
237 Returns non-zero on success.
238
239 =cut
240 */
241 int
242 i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, 
243            char *text, int len, int *bbox) {
244   FT_Error error;
245   int width;
246   int index;
247   int first;
248   int ascent = 0, descent = 0;
249   int glyph_ascent, glyph_descent;
250   FT_Glyph_Metrics *gm;
251   int start = 0;
252
253   error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64, 
254                            handle->xdpi, handle->ydpi);
255   if (error) {
256     ft2_push_message(error);
257     i_push_error(0, "setting size");
258   }
259
260   first = 1;
261   width = 0;
262   while (len--) {
263     int c = (unsigned char)*text++;
264     
265     index = FT_Get_Char_Index(handle->face, c);
266     error = FT_Load_Glyph(handle->face, index, FT_LOAD_DEFAULT);
267     if (error) {
268       ft2_push_message(error);
269       i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)", 
270                     c, index);
271       return 0;
272     }
273     gm = &handle->face->glyph->metrics;
274     glyph_ascent = gm->horiBearingY / 64;
275     glyph_descent = glyph_ascent - gm->height/64;
276     if (first) {
277       start = gm->horiBearingX / 64;
278       /* handles -ve values properly */
279       ascent = glyph_ascent;
280       descent = glyph_descent;
281       first = 0;
282     }
283
284     if (glyph_ascent > ascent)
285       ascent = glyph_ascent;
286     if (glyph_descent > descent)
287       descent = glyph_descent;
288
289     width += gm->horiAdvance / 64;
290
291     if (len == 0) {
292       /* last character 
293        handle the case where the right the of the character overlaps the 
294        right*/
295       int rightb = gm->horiAdvance - gm->horiBearingX - gm->width;
296       if (rightb < 0)
297         width -= rightb / 64;
298     }
299   }
300
301   bbox[0] = start;
302   bbox[1] = handle->face->size->metrics.descender / 64;
303   bbox[2] = width;
304   bbox[3] = handle->face->size->metrics.ascender / 64;
305   bbox[4] = descent;
306   bbox[5] = ascent;
307
308   return 1;
309 }
310
311 /*
312 =item transform_box(FT2_FontHandle *handle, int bbox[4])
313
314 bbox contains coorinates of a the top-left and bottom-right of a bounding 
315 box relative to a point.
316
317 This is then transformed and the values in bbox[4] are the top-left
318 and bottom-right of the new bounding box.
319
320 This is meant to provide the bounding box of a transformed character
321 box.  The problem is that if the character was round and is rotated,
322 the real bounding box isn't going to be much different from the
323 original, but this function will return a _bigger_ bounding box.  I
324 suppose I could work my way through the glyph outline, but that's
325 too much hard work.
326
327 =cut
328 */
329 void ft2_transform_box(FT2_Fonthandle *handle, int bbox[4]) {
330   double work[8];
331   double *matrix = handle->matrix;
332   int i;
333   
334   work[0] = matrix[0] * bbox[0] + matrix[1] * bbox[1];
335   work[1] = matrix[3] * bbox[0] + matrix[4] * bbox[1];
336   work[2] = matrix[0] * bbox[2] + matrix[1] * bbox[1];
337   work[3] = matrix[3] * bbox[2] + matrix[4] * bbox[1];
338   work[4] = matrix[0] * bbox[0] + matrix[1] * bbox[3];
339   work[5] = matrix[3] * bbox[0] + matrix[4] * bbox[3];
340   work[6] = matrix[0] * bbox[2] + matrix[1] * bbox[3];
341   work[7] = matrix[3] * bbox[2] + matrix[4] * bbox[3];
342
343   bbox[0] = floor(min(min(work[0], work[2]),min(work[4], work[6])));
344   bbox[1] = floor(min(min(work[1], work[3]),min(work[5], work[7])));
345   bbox[2] = ceil(max(max(work[0], work[2]),max(work[4], work[6])));
346   bbox[3] = ceil(max(max(work[1], work[3]),max(work[5], work[7])));
347 }
348
349 /*
350 =item expand_bounds(int bbox[4], int bbox2[4]) 
351
352 Treating bbox[] and bbox2[] as 2 bounding boxes, produces a new
353 bounding box in bbox[] that encloses both.
354
355 =cut
356 */
357 static void expand_bounds(int bbox[4], int bbox2[4]) {
358   bbox[0] = min(bbox[0], bbox2[0]);
359   bbox[1] = min(bbox[1], bbox2[1]);
360   bbox[2] = max(bbox[2], bbox2[2]);
361   bbox[3] = max(bbox[3], bbox2[3]);
362 }
363
364 /*
365 =item i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, int len, int vlayout, int utf8, int *bbox)
366
367 Retrieves bounding box information for the font at the given 
368 character width and height.
369
370 This version finds the rectangular bounding box of the glyphs, with
371 the text as transformed by the transformation matrix.  As with
372 i_ft2_bbox (bbox[0], bbox[1]) will the the offset from the start of
373 the topline to the top-left of the bounding box.  Unlike i_ft2_bbox()
374 this could be near the bottom left corner of the box.
375
376 (bbox[4], bbox[5]) is the offset to the start of the baseline.
377 (bbox[6], bbox[7]) is the offset from the start of the baseline to the
378 end of the baseline.
379
380 Returns non-zero on success.
381
382 =cut
383 */
384 int
385 i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, 
386            char *text, int len, int vlayout, int utf8, int *bbox) {
387   FT_Error error;
388   int width;
389   int index;
390   int first;
391   int ascent = 0, descent = 0;
392   int glyph_ascent, glyph_descent;
393   FT_Glyph_Metrics *gm;
394   int start = 0;
395   int work[4];
396   int bounds[4];
397   double x = 0, y = 0;
398   int i;
399   FT_GlyphSlot slot;
400   int advx, advy;
401   int loadFlags = FT_LOAD_DEFAULT;
402
403   if (vlayout)
404     loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
405
406   error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64, 
407                            handle->xdpi, handle->ydpi);
408   if (error) {
409     ft2_push_message(error);
410     i_push_error(0, "setting size");
411   }
412
413   first = 1;
414   width = 0;
415   while (len) {
416     unsigned long c;
417     if (utf8) {
418       c = utf8_advance(&text, &len);
419       if (c == ~0UL) {
420         i_push_error(0, "invalid UTF8 character");
421         return 0;
422       }
423     }
424     else {
425       c = (unsigned char)*text++;
426       --len;
427     }
428
429     index = FT_Get_Char_Index(handle->face, c);
430     error = FT_Load_Glyph(handle->face, index, loadFlags);
431     if (error) {
432       ft2_push_message(error);
433       i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)", 
434                     c, index);
435       return 0;
436     }
437     slot = handle->face->glyph; 
438     gm = &slot->metrics;
439
440     /* these probably don't mean much for vertical layouts */
441     glyph_ascent = gm->horiBearingY / 64;
442     glyph_descent = glyph_ascent - gm->height/64;
443     if (vlayout) {
444       work[0] = gm->vertBearingX;
445       work[1] = gm->vertBearingY;
446     }
447     else {
448       work[0] = gm->horiBearingX;
449       work[1] = gm->horiBearingY;
450     }
451     work[2] = gm->width  + work[0];
452     work[3] = work[1] - gm->height;
453     if (first) {
454       bbox[4] = work[0] * handle->matrix[0] + work[1] * handle->matrix[1] + handle->matrix[2];
455       bbox[5] = work[0] * handle->matrix[3] + work[1] * handle->matrix[4] + handle->matrix[5];
456       bbox[4] = bbox[4] < 0 ? -(-bbox[4] + 32)/64 : (bbox[4] + 32) / 64;
457       bbox[5] /= 64;
458     }
459     ft2_transform_box(handle, work);
460     for (i = 0; i < 4; ++i)
461       work[i] /= 64;
462     work[0] += x;
463     work[1] += y;
464     work[2] += x;
465     work[3] += y;
466     if (first) {
467       for (i = 0; i < 4; ++i)
468         bounds[i] = work[i];
469       ascent = glyph_ascent;
470       descent = glyph_descent;
471       first = 0;
472     }
473     else {
474       expand_bounds(bounds, work);
475     }
476     x += slot->advance.x / 64;
477     y += slot->advance.y / 64;
478     
479     if (glyph_ascent > ascent)
480       ascent = glyph_ascent;
481     if (glyph_descent > descent)
482       descent = glyph_descent;
483
484     if (len == 0) {
485       /* last character 
486        handle the case where the right the of the character overlaps the 
487        right*/
488       /*int rightb = gm->horiAdvance - gm->horiBearingX - gm->width;
489       if (rightb < 0)
490       width -= rightb / 64;*/
491     }
492   }
493
494   /* at this point bounds contains the bounds relative to the CP,
495      and x, y hold the final position relative to the CP */
496   /*bounds[0] -= x;
497   bounds[1] -= y;
498   bounds[2] -= x;
499   bounds[3] -= y;*/
500
501   bbox[0] = bounds[0];
502   bbox[1] = -bounds[3];
503   bbox[2] = bounds[2];
504   bbox[3] = -bounds[1];
505   bbox[6] = x;
506   bbox[7] = -y;
507
508   return 1;
509 }
510
511
512
513 static int
514 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map);
515
516 /*
517 =item i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl, double cheight, double cwidth, char *text, int len, int align, int aa)
518
519 Renders I<text> to (I<tx>, I<ty>) in I<im> using color I<cl> at the given 
520 I<cheight> and I<cwidth>.
521
522 If align is 0, then the text is rendered with the top-left of the
523 first character at (I<tx>, I<ty>).  If align is non-zero then the text
524 is rendered with (I<tx>, I<ty>) aligned with the base-line of the
525 characters.
526
527 If aa is non-zero then the text is anti-aliased.
528
529 Returns non-zero on success.
530
531 =cut
532 */
533 int
534 i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl,
535            double cheight, double cwidth, char *text, int len, int align,
536            int aa, int vlayout, int utf8) {
537   FT_Error error;
538   int index;
539   FT_Glyph_Metrics *gm;
540   int bbox[6];
541   FT_GlyphSlot slot;
542   int x, y;
543   unsigned char *bmp;
544   unsigned char map[256];
545   char last_mode = ft_pixel_mode_none; 
546   int last_grays = -1;
547   int ch;
548   i_color pel;
549   int loadFlags = FT_LOAD_DEFAULT;
550
551   if (vlayout) {
552     if (!FT_HAS_VERTICAL(handle->face)) {
553       i_push_error(0, "face has no vertical metrics");
554       return 0;
555     }
556     loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
557   }
558   if (!handle->hint)
559     loadFlags |= FT_LOAD_NO_HINTING;
560
561   /* set the base-line based on the string ascent */
562   if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox))
563     return 0;
564
565   if (!align) {
566     /* this may need adjustment */
567     tx -= bbox[0] * handle->matrix[0] + bbox[5] * handle->matrix[1] + handle->matrix[2];
568     ty += bbox[0] * handle->matrix[3] + bbox[5] * handle->matrix[4] + handle->matrix[5];
569   }
570   while (len) {
571     unsigned long c;
572     if (utf8) {
573       c = utf8_advance(&text, &len);
574       if (c == ~0UL) {
575         i_push_error(0, "invalid UTF8 character");
576         return 0;
577       }
578     }
579     else {
580       c = (unsigned char)*text++;
581       --len;
582     }
583     
584     index = FT_Get_Char_Index(handle->face, c);
585     error = FT_Load_Glyph(handle->face, index, loadFlags);
586     if (error) {
587       ft2_push_message(error);
588       i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)", 
589                     c, index);
590       return 0;
591     }
592     slot = handle->face->glyph;
593     gm = &slot->metrics;
594
595     error = FT_Render_Glyph(slot, aa ? ft_render_mode_normal : ft_render_mode_mono);
596     if (error) {
597       ft2_push_message(error);
598       i_push_errorf(0, "rendering glyph 0x%04X (character \\x%02X)");
599       return 0;
600     }
601     if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) {
602       bmp = slot->bitmap.buffer;
603       for (y = 0; y < slot->bitmap.rows; ++y) {
604         int pos = 0;
605         int bit = 0x80;
606         for (x = 0; x < slot->bitmap.width; ++x) {
607           if (bmp[pos] & bit)
608             i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, cl);
609
610           bit >>= 1;
611           if (bit == 0) {
612             bit = 0x80;
613             ++pos;
614           }
615         }
616         bmp += slot->bitmap.pitch;
617       }
618     }
619     else {
620       /* grey scale or something we can treat as greyscale */
621       /* we create a map to convert from the bitmap values to 0-255 */
622       if (last_mode != slot->bitmap.pixel_mode 
623           || last_grays != slot->bitmap.num_grays) {
624         if (!make_bmp_map(&slot->bitmap, map))
625           return 0;
626         last_mode = slot->bitmap.pixel_mode;
627         last_grays = slot->bitmap.num_grays;
628       }
629       
630       bmp = slot->bitmap.buffer;
631       for (y = 0; y < slot->bitmap.rows; ++y) {
632         for (x = 0; x < slot->bitmap.width; ++x) {
633           int value = map[bmp[x]];
634           if (value) {
635             i_gpix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, &pel);
636             for (ch = 0; ch < im->channels; ++ch) {
637               pel.channel[ch] = 
638                 ((255-value)*pel.channel[ch] + value * cl->channel[ch]) / 255;
639             }
640             i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, &pel);
641           }
642         }
643         bmp += slot->bitmap.pitch;
644       }
645     }
646
647     tx += slot->advance.x / 64;
648     ty -= slot->advance.y / 64;
649   }
650
651   return 1;
652 }
653
654 /*
655 =item i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, int channel, double cheight, double cwidth, char *text, int len, int align, int aa)
656
657 Renders I<text> to (I<tx>, I<ty>) in I<im> to I<channel> at the given 
658 I<cheight> and I<cwidth>.
659
660 If align is 0, then the text is rendered with the top-left of the
661 first character at (I<tx>, I<ty>).  If align is non-zero then the text
662 is rendered with (I<tx>, I<ty>) aligned with the base-line of the
663 characters.
664
665 If aa is non-zero then the text is anti-aliased.
666
667 Returns non-zero on success.
668
669 =cut
670 */
671
672 i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, int channel,
673          double cheight, double cwidth, char *text, int len, int align,
674          int aa, int vlayout, int utf8) {
675   int bbox[8];
676   i_img *work;
677   i_color cl, cl2;
678   int x, y;
679
680   if (vlayout && !FT_HAS_VERTICAL(handle->face)) {
681     i_push_error(0, "face has no vertical metrics");
682     return 0;
683   }
684
685   if (!i_ft2_bbox_r(handle, cheight, cwidth, text, len, vlayout, utf8, bbox))
686     return 0;
687
688   work = i_img_empty_ch(NULL, bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, 1);
689   cl.channel[0] = 255;
690   if (!i_ft2_text(handle, work, -bbox[0], -bbox[1], &cl, cheight, cwidth, 
691                   text, len, 1, aa, vlayout, utf8))
692     return 0;
693
694   if (!align) {
695     tx -= bbox[4];
696     ty += bbox[5];
697   }
698   
699   /* render to the specified channel */
700   /* this will be sped up ... */
701   for (y = 0; y < work->ysize; ++y) {
702     for (x = 0; x < work->xsize; ++x) {
703       i_gpix(work, x, y, &cl);
704       i_gpix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
705       cl2.channel[channel] = cl.channel[0];
706       i_ppix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
707     }
708   }
709
710   return 1;
711 }
712
713 /* uses a method described in fterrors.h to build an error translation
714    function
715 */
716 #undef __FT_ERRORS_H__
717 #define FT_ERRORDEF(e, v, s) case v: i_push_error(code, s); return;
718 #define FT_ERROR_START_LIST
719 #define FT_ERROR_END_LIST
720
721 /*
722 =back
723
724 =head2 Internal Functions
725
726 These functions are used in the implementation of freetyp2.c and should not
727 (usually cannot) be called from outside it.
728
729 =over
730
731 =item ft2_push_message(int code)
732
733 Pushes an error message corresponding to code onto the error stack.
734
735 =cut
736 */
737 static void ft2_push_message(int code) {
738   char unknown[40];
739
740   switch (code) {
741 #include FT_ERRORS_H
742   }
743
744   sprintf(unknown, "Unknown Freetype2 error code 0x%04X\n", code);
745   i_push_error(code, unknown);
746 }
747
748 /*
749 =item make_bmp_map(FT_Bitmap *bitmap, unsigned char *map)
750
751 Creates a map to convert grey levels from the glyphs bitmap into
752 values scaled 0..255.
753
754 =cut
755 */
756 static int
757 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map) {
758   int scale;
759   int i;
760
761   switch (bitmap->pixel_mode) {
762   case ft_pixel_mode_grays:
763     scale = bitmap->num_grays;
764     break;
765     
766   default:
767     i_push_errorf(0, "I can't handle pixel mode %d", bitmap->pixel_mode);
768     return 0;
769   }
770
771   /* build the table */
772   for (i = 0; i < scale; ++i)
773     map[i] = i * 255 / (bitmap->num_grays - 1);
774
775   return 1;
776 }
777
778 struct utf8_size {
779   int mask, expect;
780   int size;
781 };
782
783 struct utf8_size utf8_sizes[] =
784 {
785   { 0x80, 0x00, 1 },
786   { 0xE0, 0xC0, 2 },
787   { 0xF0, 0xE0, 3 },
788   { 0xF8, 0xF0, 4 },
789 };
790
791 /*
792 =item utf8_advance(char **p, int *len)
793
794 Retreive a UTF8 character from the stream.
795
796 Modifies *p and *len to indicate the consumed characters.
797
798 This doesn't support the extended UTF8 encoding used by later versions
799 of Perl.
800
801 =cut
802 */
803
804 unsigned long utf8_advance(char **p, int *len) {
805   unsigned char c;
806   int i, ci, clen = 0;
807   unsigned char codes[3];
808   if (*len == 0)
809     return ~0UL;
810   c = *(*p)++; --*len;
811
812   for (i = 0; i < sizeof(utf8_sizes)/sizeof(*utf8_sizes); ++i) {
813     if ((c & utf8_sizes[i].mask) == utf8_sizes[i].expect) {
814       clen = utf8_sizes[i].size;
815     }
816   }
817   if (clen == 0 || *len < clen-1) {
818     --*p; ++*len;
819     return ~0UL;
820   }
821
822   /* check that each character is well formed */
823   i = 1;
824   ci = 0;
825   while (i < clen) {
826     if (((*p)[ci] & 0xC0) != 0x80) {
827       --*p; ++*len;
828       return ~0UL;
829     }
830     codes[ci] = (*p)[ci];
831     ++ci; ++i;
832   }
833   *p += clen-1; *len -= clen-1;
834   if (c & 0x80) {
835     if ((c & 0xE0) == 0xC0) {
836       return ((c & 0x1F) << 6) + (codes[0] & 0x3F);
837     }
838     else if ((c & 0xF0) == 0xE0) {
839       return ((c & 0x0F) << 12) | ((codes[0] & 0x3F) << 6) | (codes[1] & 0x3f);
840     }
841     else if ((c & 0xF8) == 0xF0) {
842       return ((c & 0x07) << 18) | ((codes[0] & 0x3F) << 12) 
843               | ((codes[1] & 0x3F) << 6) | (codes[2] & 0x3F);
844     }
845     else {
846       *p -= clen; *len += clen;
847       return ~0UL;
848     }
849   }
850   else {
851     return c;
852   }
853 }
854
855 /*
856 =back
857
858 =head1 AUTHOR
859
860 Tony Cook <tony@develop-help.com>, with a fair amount of help from
861 reading the code in font.c.
862
863 =head1 SEE ALSO
864
865 font.c, Imager::Font(3), Imager(3)
866
867 http://www.freetype.org/
868
869 =cut
870 */
871