]> git.imager.perl.org - imager.git/blob - freetyp2.c
to_rgb8 doesn't crop but the void content warning said it did
[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[BOUNDING_BOX_COUNT];
16   if (!i_ft2_bbox(font, cheight, cwidth, text, length, bbox, utf8)) { 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 "imager.h"
38 #include <stdio.h>
39 #include <ft2build.h>
40 #include FT_FREETYPE_H
41 #ifdef FT_MULTIPLE_MASTERS_H
42 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
43 #define IM_FT2_MM
44 #include FT_MULTIPLE_MASTERS_H
45 #endif
46 #endif
47
48 static void ft2_push_message(int code);
49
50 static FT_Library library;
51
52 /*
53 =item i_ft2_init(void)
54
55 Initializes the Freetype 2 library.
56
57 Returns true on success, false on failure.
58
59 =cut
60 */
61 int
62 i_ft2_init(void) {
63   FT_Error error;
64
65   i_clear_error();
66   error = FT_Init_FreeType(&library);
67   if (error) {
68     ft2_push_message(error);
69     i_push_error(0, "Initializing Freetype2");
70     return 0;
71   }
72   return 1;
73 }
74
75 struct FT2_Fonthandle {
76   FT_Face face;
77   int xdpi, ydpi;
78   int hint;
79   FT_Encoding encoding;
80
81   /* used to adjust so we can align the draw point to the top-left */
82   double matrix[6];
83
84 #ifdef IM_FT2_MM
85   /* Multiple master data if any */
86   int has_mm;
87   FT_Multi_Master mm;
88 #endif
89 };
90
91 /* the following is used to select a "best" encoding */
92 static struct enc_score {
93   FT_Encoding encoding;
94   int score;
95 } enc_scores[] =
96 {
97   /* the selections here are fairly arbitrary
98      ideally we need to give the user a list of encodings available
99      and a mechanism to choose one */
100   { ft_encoding_unicode,        10 },
101   { ft_encoding_sjis,            8 },
102   { ft_encoding_gb2312,          8 },
103   { ft_encoding_big5,            8 },
104   { ft_encoding_wansung,         8 },
105   { ft_encoding_johab,           8 },  
106   { ft_encoding_latin_2,         6 },
107   { ft_encoding_apple_roman,     6 },
108   { ft_encoding_adobe_standard,  6 },
109   { ft_encoding_adobe_expert,    6 },
110 };
111
112 /*
113 =item i_ft2_new(char *name, int index)
114
115 Creates a new font object, from the file given by I<name>.  I<index>
116 is the index of the font in a file with multiple fonts, where 0 is the
117 first font.
118
119 Return NULL on failure.
120
121 =cut
122 */
123
124 FT2_Fonthandle *
125 i_ft2_new(const char *name, int index) {
126   FT_Error error;
127   FT2_Fonthandle *result;
128   FT_Face face;
129   int i, j;
130   FT_Encoding encoding;
131   int score;
132
133   mm_log((1, "i_ft2_new(name %p, index %d)\n", name, index));
134
135   i_clear_error();
136   error = FT_New_Face(library, name, index, &face);
137   if (error) {
138     ft2_push_message(error);
139     i_push_error(error, "Opening face");
140     mm_log((2, "error opening face '%s': %d\n", name, error));
141     return NULL;
142   }
143
144   encoding = face->num_charmaps ? face->charmaps[0]->encoding : ft_encoding_unicode;
145   score = 0;
146   for (i = 0; i < face->num_charmaps; ++i) {
147     FT_Encoding enc_entry = face->charmaps[i]->encoding;
148     mm_log((2, "i_ft2_new, encoding %lX platform %u encoding %u\n",
149             enc_entry, face->charmaps[i]->platform_id,
150             face->charmaps[i]->encoding_id));
151     for (j = 0; j < sizeof(enc_scores) / sizeof(*enc_scores); ++j) {
152       if (enc_scores[j].encoding == enc_entry && enc_scores[j].score > score) {
153         encoding = enc_entry;
154         score = enc_scores[j].score;
155         break;
156       }
157     }
158   }
159   FT_Select_Charmap(face, encoding);
160   mm_log((2, "i_ft2_new, selected encoding %lX\n", encoding));
161
162   result = mymalloc(sizeof(FT2_Fonthandle));
163   result->face = face;
164   result->xdpi = result->ydpi = 72;
165   result->encoding = encoding;
166
167   /* by default we disable hinting on a call to i_ft2_settransform()
168      if we don't do this, then the hinting can the untransformed text
169      to be a different size to the transformed text.
170      Obviously we have it initially enabled.
171   */
172   result->hint = 1; 
173
174   /* I originally forgot this:   :/ */
175   /*i_ft2_settransform(result, matrix); */
176   result->matrix[0] = 1; result->matrix[1] = 0; result->matrix[2] = 0;
177   result->matrix[3] = 0; result->matrix[4] = 1; result->matrix[5] = 0;
178
179 #ifdef IM_FT2_MM
180  {
181    FT_Multi_Master *mm = &result->mm;
182    int i;
183
184    if ((face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) != 0 
185        && (error = FT_Get_Multi_Master(face, mm)) == 0) {
186      mm_log((2, "MM Font, %d axes, %d designs\n", mm->num_axis, mm->num_designs));
187      for (i = 0; i < mm->num_axis; ++i) {
188        mm_log((2, "  axis %d name %s range %ld - %ld\n", i, mm->axis[i].name,
189                (long)(mm->axis[i].minimum), (long)(mm->axis[i].maximum)));
190      }
191      result->has_mm = 1;
192    }
193    else {
194      mm_log((2, "No multiple masters\n"));
195      result->has_mm = 0;
196    }
197  }
198 #endif
199
200   return result;
201 }
202
203 /*
204 =item i_ft2_destroy(FT2_Fonthandle *handle)
205
206 Destroys a font object, which must have been the return value of
207 i_ft2_new().
208
209 =cut
210 */
211 void
212 i_ft2_destroy(FT2_Fonthandle *handle) {
213   FT_Done_Face(handle->face);
214   myfree(handle);
215 }
216
217 /*
218 =item i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi)
219
220 Sets the resolution in dots per inch at which point sizes scaled, by
221 default xdpi and ydpi are 72, so that 1 point maps to 1 pixel.
222
223 Both xdpi and ydpi should be positive.
224
225 Return true on success.
226
227 =cut
228 */
229 int
230 i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi) {
231   i_clear_error();
232   if (xdpi > 0 && ydpi > 0) {
233     handle->xdpi = xdpi;
234     handle->ydpi = ydpi;
235     return 0;
236   }
237   else {
238     i_push_error(0, "resolutions must be positive");
239     return 0;
240   }
241 }
242
243 /*
244 =item i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi)
245
246 Retrieves the current horizontal and vertical resolutions at which
247 point sizes are scaled.
248
249 =cut
250 */
251 int
252 i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi) {
253   *xdpi = handle->xdpi;
254   *ydpi = handle->ydpi;
255
256   return 1;
257 }
258
259 /*
260 =item i_ft2_settransform(FT2_FontHandle *handle, double *matrix)
261
262 Sets a transormation matrix for output.
263
264 This should be a 2 x 3 matrix like:
265
266  matrix[0]   matrix[1]   matrix[2]
267  matrix[3]   matrix[4]   matrix[5]
268
269 =cut
270 */
271 int
272 i_ft2_settransform(FT2_Fonthandle *handle, const double *matrix) {
273   FT_Matrix m;
274   FT_Vector v;
275   int i;
276
277   m.xx = matrix[0] * 65536;
278   m.xy = matrix[1] * 65536;
279   v.x  = matrix[2]; /* this could be pels of 26.6 fixed - not sure */
280   m.yx = matrix[3] * 65536;
281   m.yy = matrix[4] * 65536;
282   v.y  = matrix[5]; /* see just above */
283
284   FT_Set_Transform(handle->face, &m, &v);
285
286   for (i = 0; i < 6; ++i)
287     handle->matrix[i] = matrix[i];
288   handle->hint = 0;
289
290   return 1;
291 }
292
293 /*
294 =item i_ft2_sethinting(FT2_Fonthandle *handle, int hinting)
295
296 If hinting is non-zero then glyph hinting is enabled, otherwise disabled.
297
298 i_ft2_settransform() disables hinting to prevent distortions in
299 gradual text transformations.
300
301 =cut
302 */
303 int i_ft2_sethinting(FT2_Fonthandle *handle, int hinting) {
304   handle->hint = hinting;
305   return 1;
306 }
307
308 /*
309 =item i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, int len, int *bbox)
310
311 Retrieves bounding box information for the font at the given 
312 character width and height.  This ignores the transformation matrix.
313
314 Returns non-zero on success.
315
316 =cut
317 */
318 int
319 i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, 
320            char const *text, int len, int *bbox, int utf8) {
321   FT_Error error;
322   int width;
323   int index;
324   int first;
325   int ascent = 0, descent = 0;
326   int glyph_ascent, glyph_descent;
327   FT_Glyph_Metrics *gm;
328   int start = 0;
329   int loadFlags = FT_LOAD_DEFAULT;
330   int rightb;
331
332   mm_log((1, "i_ft2_bbox(handle %p, cheight %f, cwidth %f, text %p, len %d, bbox %p)\n",
333           handle, cheight, cwidth, text, len, bbox));
334
335   error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64, 
336                            handle->xdpi, handle->ydpi);
337   if (error) {
338     ft2_push_message(error);
339     i_push_error(0, "setting size");
340   }
341
342   if (!handle->hint)
343     loadFlags |= FT_LOAD_NO_HINTING;
344
345   first = 1;
346   width = 0;
347   while (len) {
348     unsigned long c;
349     if (utf8) {
350       c = i_utf8_advance(&text, &len);
351       if (c == ~0UL) {
352         i_push_error(0, "invalid UTF8 character");
353         return 0;
354       }
355     }
356     else {
357       c = (unsigned char)*text++;
358       --len;
359     }
360
361     index = FT_Get_Char_Index(handle->face, c);
362     error = FT_Load_Glyph(handle->face, index, loadFlags);
363     if (error) {
364       ft2_push_message(error);
365       i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)", 
366                     c, index);
367       return 0;
368     }
369     gm = &handle->face->glyph->metrics;
370     glyph_ascent = gm->horiBearingY / 64;
371     glyph_descent = glyph_ascent - gm->height/64;
372     if (first) {
373       start = gm->horiBearingX / 64;
374       /* handles -ve values properly */
375       ascent = glyph_ascent;
376       descent = glyph_descent;
377       first = 0;
378     }
379
380     if (glyph_ascent > ascent)
381       ascent = glyph_ascent;
382     if (glyph_descent < descent)
383       descent = glyph_descent;
384
385     width += gm->horiAdvance / 64;
386
387     if (len == 0) {
388       /* last character 
389        handle the case where the right the of the character overlaps the 
390        right*/
391       rightb = (gm->horiAdvance - gm->horiBearingX - gm->width)/64;
392       /*if (rightb > 0)
393         rightb = 0;*/
394     }
395   }
396
397   bbox[BBOX_NEG_WIDTH] = start;
398   bbox[BBOX_GLOBAL_DESCENT] = handle->face->size->metrics.descender / 64;
399   bbox[BBOX_POS_WIDTH] = width;
400   if (rightb < 0)
401     bbox[BBOX_POS_WIDTH] -= rightb;
402   bbox[BBOX_GLOBAL_ASCENT] = handle->face->size->metrics.ascender / 64;
403   bbox[BBOX_DESCENT] = descent;
404   bbox[BBOX_ASCENT] = ascent;
405   bbox[BBOX_ADVANCE_WIDTH] = width;
406   bbox[BBOX_RIGHT_BEARING] = rightb;
407   mm_log((1, " bbox=> negw=%d glob_desc=%d pos_wid=%d glob_asc=%d desc=%d asc=%d adv_width=%d rightb=%d\n", bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5], bbox[6], bbox[7]));
408
409   return BBOX_RIGHT_BEARING + 1;
410 }
411
412 /*
413 =item transform_box(FT2_FontHandle *handle, int bbox[4])
414
415 bbox contains coorinates of a the top-left and bottom-right of a bounding 
416 box relative to a point.
417
418 This is then transformed and the values in bbox[4] are the top-left
419 and bottom-right of the new bounding box.
420
421 This is meant to provide the bounding box of a transformed character
422 box.  The problem is that if the character was round and is rotated,
423 the real bounding box isn't going to be much different from the
424 original, but this function will return a _bigger_ bounding box.  I
425 suppose I could work my way through the glyph outline, but that's
426 too much hard work.
427
428 =cut
429 */
430 void ft2_transform_box(FT2_Fonthandle *handle, int bbox[4]) {
431   double work[8];
432   double *matrix = handle->matrix;
433   
434   work[0] = matrix[0] * bbox[0] + matrix[1] * bbox[1];
435   work[1] = matrix[3] * bbox[0] + matrix[4] * bbox[1];
436   work[2] = matrix[0] * bbox[2] + matrix[1] * bbox[1];
437   work[3] = matrix[3] * bbox[2] + matrix[4] * bbox[1];
438   work[4] = matrix[0] * bbox[0] + matrix[1] * bbox[3];
439   work[5] = matrix[3] * bbox[0] + matrix[4] * bbox[3];
440   work[6] = matrix[0] * bbox[2] + matrix[1] * bbox[3];
441   work[7] = matrix[3] * bbox[2] + matrix[4] * bbox[3];
442
443   bbox[0] = floor(i_min(i_min(work[0], work[2]),i_min(work[4], work[6])));
444   bbox[1] = floor(i_min(i_min(work[1], work[3]),i_min(work[5], work[7])));
445   bbox[2] = ceil(i_max(i_max(work[0], work[2]),i_max(work[4], work[6])));
446   bbox[3] = ceil(i_max(i_max(work[1], work[3]),i_max(work[5], work[7])));
447 }
448
449 /*
450 =item expand_bounds(int bbox[4], int bbox2[4]) 
451
452 Treating bbox[] and bbox2[] as 2 bounding boxes, produces a new
453 bounding box in bbox[] that encloses both.
454
455 =cut
456 */
457 static void expand_bounds(int bbox[4], int bbox2[4]) {
458   bbox[0] = i_min(bbox[0], bbox2[0]);
459   bbox[1] = i_min(bbox[1], bbox2[1]);
460   bbox[2] = i_max(bbox[2], bbox2[2]);
461   bbox[3] = i_max(bbox[3], bbox2[3]);
462 }
463
464 /*
465 =item i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, int len, int vlayout, int utf8, int *bbox)
466
467 Retrieves bounding box information for the font at the given 
468 character width and height.
469
470 This version finds the rectangular bounding box of the glyphs, with
471 the text as transformed by the transformation matrix.  As with
472 i_ft2_bbox (bbox[0], bbox[1]) will the the offset from the start of
473 the topline to the top-left of the bounding box.  Unlike i_ft2_bbox()
474 this could be near the bottom left corner of the box.
475
476 (bbox[4], bbox[5]) is the offset to the start of the baseline.
477 (bbox[6], bbox[7]) is the offset from the start of the baseline to the
478 end of the baseline.
479
480 Returns non-zero on success.
481
482 =cut
483 */
484 int
485 i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, 
486            char const *text, int len, int vlayout, int utf8, int *bbox) {
487   FT_Error error;
488   int width;
489   int index;
490   int first;
491   int ascent = 0, descent = 0;
492   int glyph_ascent, glyph_descent;
493   FT_Glyph_Metrics *gm;
494   int work[4];
495   int bounds[4];
496   double x = 0, y = 0;
497   int i;
498   FT_GlyphSlot slot;
499   int loadFlags = FT_LOAD_DEFAULT;
500
501   if (vlayout)
502     loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
503   if (!handle->hint)
504     loadFlags |= FT_LOAD_NO_HINTING;
505
506   error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64, 
507                            handle->xdpi, handle->ydpi);
508   if (error) {
509     ft2_push_message(error);
510     i_push_error(0, "setting size");
511   }
512
513   first = 1;
514   width = 0;
515   while (len) {
516     unsigned long c;
517     if (utf8) {
518       c = i_utf8_advance(&text, &len);
519       if (c == ~0UL) {
520         i_push_error(0, "invalid UTF8 character");
521         return 0;
522       }
523     }
524     else {
525       c = (unsigned char)*text++;
526       --len;
527     }
528
529     index = FT_Get_Char_Index(handle->face, c);
530     error = FT_Load_Glyph(handle->face, index, loadFlags);
531     if (error) {
532       ft2_push_message(error);
533       i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)", 
534                     c, index);
535       return 0;
536     }
537     slot = handle->face->glyph; 
538     gm = &slot->metrics;
539
540     /* these probably don't mean much for vertical layouts */
541     glyph_ascent = gm->horiBearingY / 64;
542     glyph_descent = glyph_ascent - gm->height/64;
543     if (vlayout) {
544       work[0] = gm->vertBearingX;
545       work[1] = gm->vertBearingY;
546     }
547     else {
548       work[0] = gm->horiBearingX;
549       work[1] = gm->horiBearingY;
550     }
551     work[2] = gm->width  + work[0];
552     work[3] = work[1] - gm->height;
553     if (first) {
554       bbox[4] = work[0] * handle->matrix[0] + work[1] * handle->matrix[1] + handle->matrix[2];
555       bbox[5] = work[0] * handle->matrix[3] + work[1] * handle->matrix[4] + handle->matrix[5];
556       bbox[4] = bbox[4] < 0 ? -(-bbox[4] + 32)/64 : (bbox[4] + 32) / 64;
557       bbox[5] /= 64;
558     }
559     ft2_transform_box(handle, work);
560     for (i = 0; i < 4; ++i)
561       work[i] /= 64;
562     work[0] += x;
563     work[1] += y;
564     work[2] += x;
565     work[3] += y;
566     if (first) {
567       for (i = 0; i < 4; ++i)
568         bounds[i] = work[i];
569       ascent = glyph_ascent;
570       descent = glyph_descent;
571       first = 0;
572     }
573     else {
574       expand_bounds(bounds, work);
575     }
576     x += slot->advance.x / 64;
577     y += slot->advance.y / 64;
578
579     if (glyph_ascent > ascent)
580       ascent = glyph_ascent;
581     if (glyph_descent > descent)
582       descent = glyph_descent;
583
584     if (len == 0) {
585       /* last character 
586        handle the case where the right the of the character overlaps the 
587        right*/
588       /*int rightb = gm->horiAdvance - gm->horiBearingX - gm->width;
589       if (rightb < 0)
590       width -= rightb / 64;*/
591     }
592   }
593
594   /* at this point bounds contains the bounds relative to the CP,
595      and x, y hold the final position relative to the CP */
596   /*bounds[0] -= x;
597   bounds[1] -= y;
598   bounds[2] -= x;
599   bounds[3] -= y;*/
600
601   bbox[0] = bounds[0];
602   bbox[1] = -bounds[3];
603   bbox[2] = bounds[2];
604   bbox[3] = -bounds[1];
605   bbox[6] = x;
606   bbox[7] = -y;
607
608   return 1;
609 }
610
611 static int
612 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map);
613
614 /*
615 =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)
616
617 Renders I<text> to (I<tx>, I<ty>) in I<im> using color I<cl> at the given 
618 I<cheight> and I<cwidth>.
619
620 If align is 0, then the text is rendered with the top-left of the
621 first character at (I<tx>, I<ty>).  If align is non-zero then the text
622 is rendered with (I<tx>, I<ty>) aligned with the base-line of the
623 characters.
624
625 If aa is non-zero then the text is anti-aliased.
626
627 Returns non-zero on success.
628
629 =cut
630 */
631 int
632 i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, const i_color *cl,
633            double cheight, double cwidth, char const *text, int len, int align,
634            int aa, int vlayout, int utf8) {
635   FT_Error error;
636   int index;
637   FT_Glyph_Metrics *gm;
638   int bbox[BOUNDING_BOX_COUNT];
639   FT_GlyphSlot slot;
640   int x, y;
641   unsigned char *bmp;
642   unsigned char map[256];
643   char last_mode = ft_pixel_mode_none; 
644   int last_grays = -1;
645   int ch;
646   i_color pel;
647   int loadFlags = FT_LOAD_DEFAULT;
648
649   mm_log((1, "i_ft2_text(handle %p, im %p, tx %d, ty %d, cl %p, cheight %f, cwidth %f, text %p, len %d, align %d, aa %d)\n",
650           handle, im, tx, ty, cl, cheight, cwidth, text, align, aa));
651
652   if (vlayout) {
653     if (!FT_HAS_VERTICAL(handle->face)) {
654       i_push_error(0, "face has no vertical metrics");
655       return 0;
656     }
657     loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
658   }
659   if (!handle->hint)
660     loadFlags |= FT_LOAD_NO_HINTING;
661
662   /* set the base-line based on the string ascent */
663   if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox, utf8))
664     return 0;
665
666   if (!align) {
667     /* this may need adjustment */
668     tx -= bbox[0] * handle->matrix[0] + bbox[5] * handle->matrix[1] + handle->matrix[2];
669     ty += bbox[0] * handle->matrix[3] + bbox[5] * handle->matrix[4] + handle->matrix[5];
670   }
671   while (len) {
672     unsigned long c;
673     if (utf8) {
674       c = i_utf8_advance(&text, &len);
675       if (c == ~0UL) {
676         i_push_error(0, "invalid UTF8 character");
677         return 0;
678       }
679     }
680     else {
681       c = (unsigned char)*text++;
682       --len;
683     }
684     
685     index = FT_Get_Char_Index(handle->face, c);
686     error = FT_Load_Glyph(handle->face, index, loadFlags);
687     if (error) {
688       ft2_push_message(error);
689       i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)", 
690                     c, index);
691       return 0;
692     }
693     slot = handle->face->glyph;
694     gm = &slot->metrics;
695
696     if (gm->width) {
697       error = FT_Render_Glyph(slot, aa ? ft_render_mode_normal : ft_render_mode_mono);
698       if (error) {
699         ft2_push_message(error);
700         i_push_errorf(0, "rendering glyph 0x%04X (character \\x%02X)");
701         return 0;
702       }
703       if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) {
704         bmp = slot->bitmap.buffer;
705         for (y = 0; y < slot->bitmap.rows; ++y) {
706           int pos = 0;
707           int bit = 0x80;
708           for (x = 0; x < slot->bitmap.width; ++x) {
709             if (bmp[pos] & bit)
710               i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, cl);
711             
712             bit >>= 1;
713             if (bit == 0) {
714               bit = 0x80;
715               ++pos;
716             }
717           }
718           bmp += slot->bitmap.pitch;
719         }
720       }
721       else {
722         /* grey scale or something we can treat as greyscale */
723         /* we create a map to convert from the bitmap values to 0-255 */
724         if (last_mode != slot->bitmap.pixel_mode 
725             || last_grays != slot->bitmap.num_grays) {
726           if (!make_bmp_map(&slot->bitmap, map))
727             return 0;
728           last_mode = slot->bitmap.pixel_mode;
729           last_grays = slot->bitmap.num_grays;
730         }
731         
732         bmp = slot->bitmap.buffer;
733         for (y = 0; y < slot->bitmap.rows; ++y) {
734           for (x = 0; x < slot->bitmap.width; ++x) {
735             int value = map[bmp[x]];
736             if (value) {
737               i_gpix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, &pel);
738               for (ch = 0; ch < im->channels; ++ch) {
739                 pel.channel[ch] = 
740                   ((255-value)*pel.channel[ch] + value * cl->channel[ch]) / 255;
741               }
742               i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, &pel);
743             }
744           }
745           bmp += slot->bitmap.pitch;
746         }
747       }
748     }
749
750     tx += slot->advance.x / 64;
751     ty -= slot->advance.y / 64;
752   }
753
754   return 1;
755 }
756
757 /*
758 =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)
759
760 Renders I<text> to (I<tx>, I<ty>) in I<im> to I<channel> at the given 
761 I<cheight> and I<cwidth>.
762
763 If align is 0, then the text is rendered with the top-left of the
764 first character at (I<tx>, I<ty>).  If align is non-zero then the text
765 is rendered with (I<tx>, I<ty>) aligned with the base-line of the
766 characters.
767
768 If aa is non-zero then the text is anti-aliased.
769
770 Returns non-zero on success.
771
772 =cut
773 */
774
775 int
776 i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, int channel,
777          double cheight, double cwidth, char const *text, int len, int align,
778          int aa, int vlayout, int utf8) {
779   int bbox[8];
780   i_img *work;
781   i_color cl, cl2;
782   int x, y;
783
784   mm_log((1, "i_ft2_cp(handle %p, im %p, tx %d, ty %d, channel %d, cheight %f, cwidth %f, text %p, len %d, ...)\n", 
785           handle, im, tx, ty, channel, cheight, cwidth, text, len));
786
787   if (vlayout && !FT_HAS_VERTICAL(handle->face)) {
788     i_push_error(0, "face has no vertical metrics");
789     return 0;
790   }
791
792   if (!i_ft2_bbox_r(handle, cheight, cwidth, text, len, vlayout, utf8, bbox))
793     return 0;
794
795   work = i_img_empty_ch(NULL, bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, 1);
796   cl.channel[0] = 255;
797   if (!i_ft2_text(handle, work, -bbox[0], -bbox[1], &cl, cheight, cwidth, 
798                   text, len, 1, aa, vlayout, utf8))
799     return 0;
800
801   if (!align) {
802     tx -= bbox[4];
803     ty += bbox[5];
804   }
805   
806   /* render to the specified channel */
807   /* this will be sped up ... */
808   for (y = 0; y < work->ysize; ++y) {
809     for (x = 0; x < work->xsize; ++x) {
810       i_gpix(work, x, y, &cl);
811       i_gpix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
812       cl2.channel[channel] = cl.channel[0];
813       i_ppix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
814     }
815   }
816   i_img_destroy(work);
817   return 1;
818 }
819
820 /*
821 =item i_ft2_has_chars(handle, char *text, int len, int utf8, char *out)
822
823 Check if the given characters are defined by the font.
824
825 Returns the number of characters that were checked.
826
827 =cut
828 */
829 int i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, int len, 
830                     int utf8, char *out) {
831   int count = 0;
832   mm_log((1, "i_ft2_has_chars(handle %p, text %p, len %d, utf8 %d)\n", 
833           handle, text, len, utf8));
834
835   while (len) {
836     unsigned long c;
837     int index;
838     if (utf8) {
839       c = i_utf8_advance(&text, &len);
840       if (c == ~0UL) {
841         i_push_error(0, "invalid UTF8 character");
842         return 0;
843       }
844     }
845     else {
846       c = (unsigned char)*text++;
847       --len;
848     }
849     
850     index = FT_Get_Char_Index(handle->face, c);
851     *out++ = index != 0;
852     ++count;
853   }
854
855   return count;
856 }
857
858 /* uses a method described in fterrors.h to build an error translation
859    function
860 */
861 #undef __FTERRORS_H__
862 #define FT_ERRORDEF(e, v, s) case v: i_push_error(code, s); return;
863 #define FT_ERROR_START_LIST 
864 #define FT_ERROR_END_LIST 
865
866 /*
867 =back
868
869 =head2 Internal Functions
870
871 These functions are used in the implementation of freetyp2.c and should not
872 (usually cannot) be called from outside it.
873
874 =over
875
876 =item ft2_push_message(int code)
877
878 Pushes an error message corresponding to code onto the error stack.
879
880 =cut
881 */
882 static void ft2_push_message(int code) {
883   char unknown[40];
884
885   switch (code) {
886 #include FT_ERRORS_H
887   }
888
889   sprintf(unknown, "Unknown Freetype2 error code 0x%04X\n", code);
890   i_push_error(code, unknown);
891 }
892
893 /*
894 =item make_bmp_map(FT_Bitmap *bitmap, unsigned char *map)
895
896 Creates a map to convert grey levels from the glyphs bitmap into
897 values scaled 0..255.
898
899 =cut
900 */
901 static int
902 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map) {
903   int scale;
904   int i;
905
906   switch (bitmap->pixel_mode) {
907   case ft_pixel_mode_grays:
908     scale = bitmap->num_grays;
909     break;
910     
911   default:
912     i_push_errorf(0, "I can't handle pixel mode %d", bitmap->pixel_mode);
913     return 0;
914   }
915
916   /* build the table */
917   for (i = 0; i < scale; ++i)
918     map[i] = i * 255 / (bitmap->num_grays - 1);
919
920   return 1;
921 }
922
923 /* FREETYPE_PATCH was introduced in 2.0.6, we don't want a false 
924    positive on 2.0.0 to 2.0.4, so we accept a false negative in 2.0.5 */
925 #ifndef FREETYPE_PATCH
926 #define FREETYPE_PATCH 4
927 #endif
928
929 /* FT_Get_Postscript_Name() was introduced in FT2.0.5 */
930 #define IM_HAS_FACE_NAME (FREETYPE_MINOR > 0 || FREETYPE_PATCH >= 5)
931 /* #define IM_HAS_FACE_NAME 0 */ 
932
933 /*
934 =item i_ft2_face_name(handle, name_buf, name_buf_size)
935
936 Fills the given buffer with the Postscript Face name of the font,
937 if there is one.
938
939 =cut
940 */
941
942 int
943 i_ft2_face_name(FT2_Fonthandle *handle, char *name_buf, size_t name_buf_size) {
944 #if IM_HAS_FACE_NAME
945   char const *name = FT_Get_Postscript_Name(handle->face);
946
947   i_clear_error();
948
949   if (name) {
950     strncpy(name_buf, name, name_buf_size);
951     name_buf[name_buf_size-1] = '\0';
952
953     return strlen(name) + 1;
954   }
955   else {
956     i_push_error(0, "no face name available");
957     *name_buf = '\0';
958
959     return 0;
960   }
961 #else
962   i_clear_error();
963   i_push_error(0, "Freetype 2.0.6 or later required");
964   *name_buf = '\0';
965
966   return 0;
967 #endif
968 }
969
970 int
971 i_ft2_can_face_name(void) {
972   return IM_HAS_FACE_NAME;
973 }
974
975 /* FT_Has_PS_Glyph_Names() was introduced in FT2.1.1 */
976 /* well, I assume FREETYPE_MAJOR is 2, since we're here */
977 #if FREETYPE_MINOR < 1 || (FREETYPE_MINOR == 1 && FREETYPE_PATCH < 1)
978 #define FT_Has_PS_Glyph_Names(face) (FT_HAS_GLYPH_NAMES(face))
979 #endif
980
981 int
982 i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned long ch, char *name_buf, 
983                  size_t name_buf_size, int reliable_only) {
984 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
985   i_clear_error();
986   *name_buf = '\0';
987   i_push_error(0, "FT2 configured without glyph name support");
988
989   return 0;
990 #else
991   FT_UInt index;
992
993   i_clear_error();
994
995   if (!FT_HAS_GLYPH_NAMES(handle->face)) {
996     i_push_error(0, "no glyph names in font");
997     *name_buf = '\0';
998     return 0;
999   }
1000   if (reliable_only && !FT_Has_PS_Glyph_Names(handle->face)) {
1001     i_push_error(0, "no reliable glyph names in font - set reliable_only to 0 to try anyway");
1002     *name_buf = '\0';
1003     return 0;
1004   }
1005
1006   index = FT_Get_Char_Index(handle->face, ch);
1007   
1008   if (index) {
1009     FT_Error error = FT_Get_Glyph_Name(handle->face, index, name_buf, 
1010                                        name_buf_size);
1011     if (error) {
1012       ft2_push_message(error);
1013       *name_buf = '\0';
1014       return 0;
1015     }
1016     if (*name_buf) {
1017       return strlen(name_buf) + 1;
1018     }
1019     else {
1020       return 0;
1021     }
1022   }
1023   else {
1024     i_push_error(0, "no glyph for that character");
1025     *name_buf = 0;
1026     return 0;
1027   }
1028 #endif
1029 }
1030
1031 int
1032 i_ft2_can_do_glyph_names(void) {
1033 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1034   return 0;
1035 #else
1036   return 1;
1037 #endif
1038 }
1039
1040 int 
1041 i_ft2_face_has_glyph_names(FT2_Fonthandle *handle) {
1042 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1043   return 0;
1044 #else
1045   return FT_Has_PS_Glyph_Names(handle->face);
1046 #endif
1047 }
1048
1049 int
1050 i_ft2_is_multiple_master(FT2_Fonthandle *handle) {
1051   i_clear_error();
1052 #ifdef IM_FT2_MM
1053   return handle->has_mm;
1054 #else
1055   return 0;
1056 #endif
1057 }
1058
1059 int
1060 i_ft2_get_multiple_masters(FT2_Fonthandle *handle, i_font_mm *mm) {
1061 #ifdef IM_FT2_MM
1062   int i;
1063   FT_Multi_Master *mms = &handle->mm;
1064
1065   i_clear_error();
1066   if (!handle->has_mm) {
1067     i_push_error(0, "Font has no multiple masters");
1068     return 0;
1069   }
1070   mm->num_axis = mms->num_axis;
1071   mm->num_designs = mms->num_designs;
1072   for (i = 0; i < mms->num_axis; ++i) {
1073     mm->axis[i].name = mms->axis[i].name;
1074     mm->axis[i].minimum = mms->axis[i].minimum;
1075     mm->axis[i].maximum = mms->axis[i].maximum;
1076   }
1077
1078   return 1;
1079 #else
1080   i_clear_error();
1081   i_push_error(0, "Multiple master functions unavailable");
1082   return 0;
1083 #endif
1084 }
1085
1086 int
1087 i_ft2_set_mm_coords(FT2_Fonthandle *handle, int coord_count, const long *coords) {
1088 #ifdef IM_FT2_MM
1089   int i;
1090   FT_Long ftcoords[T1_MAX_MM_AXIS];
1091   FT_Error error;
1092
1093   i_clear_error();
1094   if (!handle->has_mm) {
1095     i_push_error(0, "Font has no multiple masters");
1096     return 0;
1097   }
1098   if (coord_count != handle->mm.num_axis) {
1099     i_push_error(0, "Number of MM coords doesn't match MM axis count");
1100     return 0;
1101   }
1102   for (i = 0; i < coord_count; ++i)
1103     ftcoords[i] = coords[i];
1104
1105   error = FT_Set_MM_Design_Coordinates(handle->face, coord_count, ftcoords);
1106   if (error) {
1107     ft2_push_message(error);
1108     return 0;
1109   }
1110   
1111   return 1;
1112 #else 
1113   i_clear_error();
1114   i_push_error(0, "Multiple master functions unavailable");
1115
1116   return 0;
1117 #endif
1118 }
1119
1120 /*
1121 =back
1122
1123 =head1 AUTHOR
1124
1125 Tony Cook <tony@develop-help.com>, with a fair amount of help from
1126 reading the code in font.c.
1127
1128 =head1 SEE ALSO
1129
1130 font.c, Imager::Font(3), Imager(3)
1131
1132 http://www.freetype.org/
1133
1134 =cut
1135 */
1136