- constify the Imager API
[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     error = FT_Render_Glyph(slot, aa ? ft_render_mode_normal : ft_render_mode_mono);
697     if (error) {
698       ft2_push_message(error);
699       i_push_errorf(0, "rendering glyph 0x%04X (character \\x%02X)");
700       return 0;
701     }
702     if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) {
703       bmp = slot->bitmap.buffer;
704       for (y = 0; y < slot->bitmap.rows; ++y) {
705         int pos = 0;
706         int bit = 0x80;
707         for (x = 0; x < slot->bitmap.width; ++x) {
708           if (bmp[pos] & bit)
709             i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, cl);
710
711           bit >>= 1;
712           if (bit == 0) {
713             bit = 0x80;
714             ++pos;
715           }
716         }
717         bmp += slot->bitmap.pitch;
718       }
719     }
720     else {
721       /* grey scale or something we can treat as greyscale */
722       /* we create a map to convert from the bitmap values to 0-255 */
723       if (last_mode != slot->bitmap.pixel_mode 
724           || last_grays != slot->bitmap.num_grays) {
725         if (!make_bmp_map(&slot->bitmap, map))
726           return 0;
727         last_mode = slot->bitmap.pixel_mode;
728         last_grays = slot->bitmap.num_grays;
729       }
730       
731       bmp = slot->bitmap.buffer;
732       for (y = 0; y < slot->bitmap.rows; ++y) {
733         for (x = 0; x < slot->bitmap.width; ++x) {
734           int value = map[bmp[x]];
735           if (value) {
736             i_gpix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, &pel);
737             for (ch = 0; ch < im->channels; ++ch) {
738               pel.channel[ch] = 
739                 ((255-value)*pel.channel[ch] + value * cl->channel[ch]) / 255;
740             }
741             i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, &pel);
742           }
743         }
744         bmp += slot->bitmap.pitch;
745       }
746     }
747
748     tx += slot->advance.x / 64;
749     ty -= slot->advance.y / 64;
750   }
751
752   return 1;
753 }
754
755 /*
756 =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)
757
758 Renders I<text> to (I<tx>, I<ty>) in I<im> to I<channel> at the given 
759 I<cheight> and I<cwidth>.
760
761 If align is 0, then the text is rendered with the top-left of the
762 first character at (I<tx>, I<ty>).  If align is non-zero then the text
763 is rendered with (I<tx>, I<ty>) aligned with the base-line of the
764 characters.
765
766 If aa is non-zero then the text is anti-aliased.
767
768 Returns non-zero on success.
769
770 =cut
771 */
772
773 int
774 i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, int channel,
775          double cheight, double cwidth, char const *text, int len, int align,
776          int aa, int vlayout, int utf8) {
777   int bbox[8];
778   i_img *work;
779   i_color cl, cl2;
780   int x, y;
781
782   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", 
783           handle, im, tx, ty, channel, cheight, cwidth, text, len));
784
785   if (vlayout && !FT_HAS_VERTICAL(handle->face)) {
786     i_push_error(0, "face has no vertical metrics");
787     return 0;
788   }
789
790   if (!i_ft2_bbox_r(handle, cheight, cwidth, text, len, vlayout, utf8, bbox))
791     return 0;
792
793   work = i_img_empty_ch(NULL, bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, 1);
794   cl.channel[0] = 255;
795   if (!i_ft2_text(handle, work, -bbox[0], -bbox[1], &cl, cheight, cwidth, 
796                   text, len, 1, aa, vlayout, utf8))
797     return 0;
798
799   if (!align) {
800     tx -= bbox[4];
801     ty += bbox[5];
802   }
803   
804   /* render to the specified channel */
805   /* this will be sped up ... */
806   for (y = 0; y < work->ysize; ++y) {
807     for (x = 0; x < work->xsize; ++x) {
808       i_gpix(work, x, y, &cl);
809       i_gpix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
810       cl2.channel[channel] = cl.channel[0];
811       i_ppix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
812     }
813   }
814   i_img_destroy(work);
815   return 1;
816 }
817
818 /*
819 =item i_ft2_has_chars(handle, char *text, int len, int utf8, char *out)
820
821 Check if the given characters are defined by the font.
822
823 Returns the number of characters that were checked.
824
825 =cut
826 */
827 int i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, int len, 
828                     int utf8, char *out) {
829   int count = 0;
830   mm_log((1, "i_ft2_has_chars(handle %p, text %p, len %d, utf8 %d)\n", 
831           handle, text, len, utf8));
832
833   while (len) {
834     unsigned long c;
835     int index;
836     if (utf8) {
837       c = i_utf8_advance(&text, &len);
838       if (c == ~0UL) {
839         i_push_error(0, "invalid UTF8 character");
840         return 0;
841       }
842     }
843     else {
844       c = (unsigned char)*text++;
845       --len;
846     }
847     
848     index = FT_Get_Char_Index(handle->face, c);
849     *out++ = index != 0;
850     ++count;
851   }
852
853   return count;
854 }
855
856 /* uses a method described in fterrors.h to build an error translation
857    function
858 */
859 #undef __FTERRORS_H__
860 #define FT_ERRORDEF(e, v, s) case v: i_push_error(code, s); return;
861 #define FT_ERROR_START_LIST 
862 #define FT_ERROR_END_LIST 
863
864 /*
865 =back
866
867 =head2 Internal Functions
868
869 These functions are used in the implementation of freetyp2.c and should not
870 (usually cannot) be called from outside it.
871
872 =over
873
874 =item ft2_push_message(int code)
875
876 Pushes an error message corresponding to code onto the error stack.
877
878 =cut
879 */
880 static void ft2_push_message(int code) {
881   char unknown[40];
882
883   switch (code) {
884 #include FT_ERRORS_H
885   }
886
887   sprintf(unknown, "Unknown Freetype2 error code 0x%04X\n", code);
888   i_push_error(code, unknown);
889 }
890
891 /*
892 =item make_bmp_map(FT_Bitmap *bitmap, unsigned char *map)
893
894 Creates a map to convert grey levels from the glyphs bitmap into
895 values scaled 0..255.
896
897 =cut
898 */
899 static int
900 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map) {
901   int scale;
902   int i;
903
904   switch (bitmap->pixel_mode) {
905   case ft_pixel_mode_grays:
906     scale = bitmap->num_grays;
907     break;
908     
909   default:
910     i_push_errorf(0, "I can't handle pixel mode %d", bitmap->pixel_mode);
911     return 0;
912   }
913
914   /* build the table */
915   for (i = 0; i < scale; ++i)
916     map[i] = i * 255 / (bitmap->num_grays - 1);
917
918   return 1;
919 }
920
921 /* FREETYPE_PATCH was introduced in 2.0.6, we don't want a false 
922    positive on 2.0.0 to 2.0.4, so we accept a false negative in 2.0.5 */
923 #ifndef FREETYPE_PATCH
924 #define FREETYPE_PATCH 4
925 #endif
926
927 /* FT_Get_Postscript_Name() was introduced in FT2.0.5 */
928 #define IM_HAS_FACE_NAME (FREETYPE_MINOR > 0 || FREETYPE_PATCH >= 5)
929 /* #define IM_HAS_FACE_NAME 0 */ 
930
931 /*
932 =item i_ft2_face_name(handle, name_buf, name_buf_size)
933
934 Fills the given buffer with the Postscript Face name of the font,
935 if there is one.
936
937 =cut
938 */
939
940 int
941 i_ft2_face_name(FT2_Fonthandle *handle, char *name_buf, size_t name_buf_size) {
942 #if IM_HAS_FACE_NAME
943   char const *name = FT_Get_Postscript_Name(handle->face);
944
945   i_clear_error();
946
947   if (name) {
948     strncpy(name_buf, name, name_buf_size);
949     name_buf[name_buf_size-1] = '\0';
950
951     return strlen(name) + 1;
952   }
953   else {
954     i_push_error(0, "no face name available");
955     *name_buf = '\0';
956
957     return 0;
958   }
959 #else
960   i_clear_error();
961   i_push_error(0, "Freetype 2.0.6 or later required");
962   *name_buf = '\0';
963
964   return 0;
965 #endif
966 }
967
968 int
969 i_ft2_can_face_name(void) {
970   return IM_HAS_FACE_NAME;
971 }
972
973 /* FT_Has_PS_Glyph_Names() was introduced in FT2.1.1 */
974 /* well, I assume FREETYPE_MAJOR is 2, since we're here */
975 #if FREETYPE_MINOR < 1 || (FREETYPE_MINOR == 1 && FREETYPE_PATCH < 1)
976 #define FT_Has_PS_Glyph_Names(face) (FT_HAS_GLYPH_NAMES(face))
977 #endif
978
979 int
980 i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned long ch, char *name_buf, 
981                  size_t name_buf_size, int reliable_only) {
982 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
983   i_clear_error();
984   *name_buf = '\0';
985   i_push_error(0, "FT2 configured without glyph name support");
986
987   return 0;
988 #else
989   FT_UInt index;
990
991   i_clear_error();
992
993   if (!FT_HAS_GLYPH_NAMES(handle->face)) {
994     i_push_error(0, "no glyph names in font");
995     *name_buf = '\0';
996     return 0;
997   }
998   if (reliable_only && !FT_Has_PS_Glyph_Names(handle->face)) {
999     i_push_error(0, "no reliable glyph names in font - set reliable_only to 0 to try anyway");
1000     *name_buf = '\0';
1001     return 0;
1002   }
1003
1004   index = FT_Get_Char_Index(handle->face, ch);
1005   
1006   if (index) {
1007     FT_Error error = FT_Get_Glyph_Name(handle->face, index, name_buf, 
1008                                        name_buf_size);
1009     if (error) {
1010       ft2_push_message(error);
1011       *name_buf = '\0';
1012       return 0;
1013     }
1014     if (*name_buf) {
1015       return strlen(name_buf) + 1;
1016     }
1017     else {
1018       return 0;
1019     }
1020   }
1021   else {
1022     i_push_error(0, "no glyph for that character");
1023     *name_buf = 0;
1024     return 0;
1025   }
1026 #endif
1027 }
1028
1029 int
1030 i_ft2_can_do_glyph_names(void) {
1031 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1032   return 0;
1033 #else
1034   return 1;
1035 #endif
1036 }
1037
1038 int 
1039 i_ft2_face_has_glyph_names(FT2_Fonthandle *handle) {
1040 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1041   return 0;
1042 #else
1043   return FT_Has_PS_Glyph_Names(handle->face);
1044 #endif
1045 }
1046
1047 int
1048 i_ft2_is_multiple_master(FT2_Fonthandle *handle) {
1049   i_clear_error();
1050 #ifdef IM_FT2_MM
1051   return handle->has_mm;
1052 #else
1053   return 0;
1054 #endif
1055 }
1056
1057 int
1058 i_ft2_get_multiple_masters(FT2_Fonthandle *handle, i_font_mm *mm) {
1059 #ifdef IM_FT2_MM
1060   int i;
1061   FT_Multi_Master *mms = &handle->mm;
1062
1063   i_clear_error();
1064   if (!handle->has_mm) {
1065     i_push_error(0, "Font has no multiple masters");
1066     return 0;
1067   }
1068   mm->num_axis = mms->num_axis;
1069   mm->num_designs = mms->num_designs;
1070   for (i = 0; i < mms->num_axis; ++i) {
1071     mm->axis[i].name = mms->axis[i].name;
1072     mm->axis[i].minimum = mms->axis[i].minimum;
1073     mm->axis[i].maximum = mms->axis[i].maximum;
1074   }
1075
1076   return 1;
1077 #else
1078   i_clear_error();
1079   i_push_error(0, "Multiple master functions unavailable");
1080   return 0;
1081 #endif
1082 }
1083
1084 int
1085 i_ft2_set_mm_coords(FT2_Fonthandle *handle, int coord_count, const long *coords) {
1086 #ifdef IM_FT2_MM
1087   int i;
1088   FT_Long ftcoords[T1_MAX_MM_AXIS];
1089   FT_Error error;
1090
1091   i_clear_error();
1092   if (!handle->has_mm) {
1093     i_push_error(0, "Font has no multiple masters");
1094     return 0;
1095   }
1096   if (coord_count != handle->mm.num_axis) {
1097     i_push_error(0, "Number of MM coords doesn't match MM axis count");
1098     return 0;
1099   }
1100   for (i = 0; i < coord_count; ++i)
1101     ftcoords[i] = coords[i];
1102
1103   error = FT_Set_MM_Design_Coordinates(handle->face, coord_count, ftcoords);
1104   if (error) {
1105     ft2_push_message(error);
1106     return 0;
1107   }
1108   
1109   return 1;
1110 #else 
1111   i_clear_error();
1112   i_push_error(0, "Multiple master functions unavailable");
1113
1114   return 0;
1115 #endif
1116 }
1117
1118 /*
1119 =back
1120
1121 =head1 AUTHOR
1122
1123 Tony Cook <tony@develop-help.com>, with a fair amount of help from
1124 reading the code in font.c.
1125
1126 =head1 SEE ALSO
1127
1128 font.c, Imager::Font(3), Imager(3)
1129
1130 http://www.freetype.org/
1131
1132 =cut
1133 */
1134