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