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