]> git.imager.perl.org - imager.git/blob - freetyp2.c
- reading an image with an idstring of 128 or more bytes would result
[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 "image.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(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, 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 - rightb;
400   bbox[BBOX_GLOBAL_ASCENT] = handle->face->size->metrics.ascender / 64;
401   bbox[BBOX_DESCENT] = descent;
402   bbox[BBOX_ASCENT] = ascent;
403   bbox[BBOX_ADVANCE_WIDTH] = width;
404
405   return BBOX_ADVANCE_WIDTH + 1;
406 }
407
408 /*
409 =item transform_box(FT2_FontHandle *handle, int bbox[4])
410
411 bbox contains coorinates of a the top-left and bottom-right of a bounding 
412 box relative to a point.
413
414 This is then transformed and the values in bbox[4] are the top-left
415 and bottom-right of the new bounding box.
416
417 This is meant to provide the bounding box of a transformed character
418 box.  The problem is that if the character was round and is rotated,
419 the real bounding box isn't going to be much different from the
420 original, but this function will return a _bigger_ bounding box.  I
421 suppose I could work my way through the glyph outline, but that's
422 too much hard work.
423
424 =cut
425 */
426 void ft2_transform_box(FT2_Fonthandle *handle, int bbox[4]) {
427   double work[8];
428   double *matrix = handle->matrix;
429   
430   work[0] = matrix[0] * bbox[0] + matrix[1] * bbox[1];
431   work[1] = matrix[3] * bbox[0] + matrix[4] * bbox[1];
432   work[2] = matrix[0] * bbox[2] + matrix[1] * bbox[1];
433   work[3] = matrix[3] * bbox[2] + matrix[4] * bbox[1];
434   work[4] = matrix[0] * bbox[0] + matrix[1] * bbox[3];
435   work[5] = matrix[3] * bbox[0] + matrix[4] * bbox[3];
436   work[6] = matrix[0] * bbox[2] + matrix[1] * bbox[3];
437   work[7] = matrix[3] * bbox[2] + matrix[4] * bbox[3];
438
439   bbox[0] = floor(i_min(i_min(work[0], work[2]),i_min(work[4], work[6])));
440   bbox[1] = floor(i_min(i_min(work[1], work[3]),i_min(work[5], work[7])));
441   bbox[2] = ceil(i_max(i_max(work[0], work[2]),i_max(work[4], work[6])));
442   bbox[3] = ceil(i_max(i_max(work[1], work[3]),i_max(work[5], work[7])));
443 }
444
445 /*
446 =item expand_bounds(int bbox[4], int bbox2[4]) 
447
448 Treating bbox[] and bbox2[] as 2 bounding boxes, produces a new
449 bounding box in bbox[] that encloses both.
450
451 =cut
452 */
453 static void expand_bounds(int bbox[4], int bbox2[4]) {
454   bbox[0] = i_min(bbox[0], bbox2[0]);
455   bbox[1] = i_min(bbox[1], bbox2[1]);
456   bbox[2] = i_max(bbox[2], bbox2[2]);
457   bbox[3] = i_max(bbox[3], bbox2[3]);
458 }
459
460 /*
461 =item i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, int len, int vlayout, int utf8, int *bbox)
462
463 Retrieves bounding box information for the font at the given 
464 character width and height.
465
466 This version finds the rectangular bounding box of the glyphs, with
467 the text as transformed by the transformation matrix.  As with
468 i_ft2_bbox (bbox[0], bbox[1]) will the the offset from the start of
469 the topline to the top-left of the bounding box.  Unlike i_ft2_bbox()
470 this could be near the bottom left corner of the box.
471
472 (bbox[4], bbox[5]) is the offset to the start of the baseline.
473 (bbox[6], bbox[7]) is the offset from the start of the baseline to the
474 end of the baseline.
475
476 Returns non-zero on success.
477
478 =cut
479 */
480 int
481 i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, 
482            char const *text, int len, int vlayout, int utf8, int *bbox) {
483   FT_Error error;
484   int width;
485   int index;
486   int first;
487   int ascent = 0, descent = 0;
488   int glyph_ascent, glyph_descent;
489   FT_Glyph_Metrics *gm;
490   int work[4];
491   int bounds[4];
492   double x = 0, y = 0;
493   int i;
494   FT_GlyphSlot slot;
495   int loadFlags = FT_LOAD_DEFAULT;
496
497   if (vlayout)
498     loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
499   if (!handle->hint)
500     loadFlags |= FT_LOAD_NO_HINTING;
501
502   error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64, 
503                            handle->xdpi, handle->ydpi);
504   if (error) {
505     ft2_push_message(error);
506     i_push_error(0, "setting size");
507   }
508
509   first = 1;
510   width = 0;
511   while (len) {
512     unsigned long c;
513     if (utf8) {
514       c = i_utf8_advance(&text, &len);
515       if (c == ~0UL) {
516         i_push_error(0, "invalid UTF8 character");
517         return 0;
518       }
519     }
520     else {
521       c = (unsigned char)*text++;
522       --len;
523     }
524
525     index = FT_Get_Char_Index(handle->face, c);
526     error = FT_Load_Glyph(handle->face, index, loadFlags);
527     if (error) {
528       ft2_push_message(error);
529       i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)", 
530                     c, index);
531       return 0;
532     }
533     slot = handle->face->glyph; 
534     gm = &slot->metrics;
535
536     /* these probably don't mean much for vertical layouts */
537     glyph_ascent = gm->horiBearingY / 64;
538     glyph_descent = glyph_ascent - gm->height/64;
539     if (vlayout) {
540       work[0] = gm->vertBearingX;
541       work[1] = gm->vertBearingY;
542     }
543     else {
544       work[0] = gm->horiBearingX;
545       work[1] = gm->horiBearingY;
546     }
547     work[2] = gm->width  + work[0];
548     work[3] = work[1] - gm->height;
549     if (first) {
550       bbox[4] = work[0] * handle->matrix[0] + work[1] * handle->matrix[1] + handle->matrix[2];
551       bbox[5] = work[0] * handle->matrix[3] + work[1] * handle->matrix[4] + handle->matrix[5];
552       bbox[4] = bbox[4] < 0 ? -(-bbox[4] + 32)/64 : (bbox[4] + 32) / 64;
553       bbox[5] /= 64;
554     }
555     ft2_transform_box(handle, work);
556     for (i = 0; i < 4; ++i)
557       work[i] /= 64;
558     work[0] += x;
559     work[1] += y;
560     work[2] += x;
561     work[3] += y;
562     if (first) {
563       for (i = 0; i < 4; ++i)
564         bounds[i] = work[i];
565       ascent = glyph_ascent;
566       descent = glyph_descent;
567       first = 0;
568     }
569     else {
570       expand_bounds(bounds, work);
571     }
572     x += slot->advance.x / 64;
573     y += slot->advance.y / 64;
574
575     if (glyph_ascent > ascent)
576       ascent = glyph_ascent;
577     if (glyph_descent > descent)
578       descent = glyph_descent;
579
580     if (len == 0) {
581       /* last character 
582        handle the case where the right the of the character overlaps the 
583        right*/
584       /*int rightb = gm->horiAdvance - gm->horiBearingX - gm->width;
585       if (rightb < 0)
586       width -= rightb / 64;*/
587     }
588   }
589
590   /* at this point bounds contains the bounds relative to the CP,
591      and x, y hold the final position relative to the CP */
592   /*bounds[0] -= x;
593   bounds[1] -= y;
594   bounds[2] -= x;
595   bounds[3] -= y;*/
596
597   bbox[0] = bounds[0];
598   bbox[1] = -bounds[3];
599   bbox[2] = bounds[2];
600   bbox[3] = -bounds[1];
601   bbox[6] = x;
602   bbox[7] = -y;
603
604   return 1;
605 }
606
607 static int
608 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map);
609
610 /*
611 =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)
612
613 Renders I<text> to (I<tx>, I<ty>) in I<im> using color I<cl> at the given 
614 I<cheight> and I<cwidth>.
615
616 If align is 0, then the text is rendered with the top-left of the
617 first character at (I<tx>, I<ty>).  If align is non-zero then the text
618 is rendered with (I<tx>, I<ty>) aligned with the base-line of the
619 characters.
620
621 If aa is non-zero then the text is anti-aliased.
622
623 Returns non-zero on success.
624
625 =cut
626 */
627 int
628 i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl,
629            double cheight, double cwidth, char const *text, int len, int align,
630            int aa, int vlayout, int utf8) {
631   FT_Error error;
632   int index;
633   FT_Glyph_Metrics *gm;
634   int bbox[BOUNDING_BOX_COUNT];
635   FT_GlyphSlot slot;
636   int x, y;
637   unsigned char *bmp;
638   unsigned char map[256];
639   char last_mode = ft_pixel_mode_none; 
640   int last_grays = -1;
641   int ch;
642   i_color pel;
643   int loadFlags = FT_LOAD_DEFAULT;
644
645   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",
646           handle, im, tx, ty, cl, cheight, cwidth, text, align, aa));
647
648   if (vlayout) {
649     if (!FT_HAS_VERTICAL(handle->face)) {
650       i_push_error(0, "face has no vertical metrics");
651       return 0;
652     }
653     loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
654   }
655   if (!handle->hint)
656     loadFlags |= FT_LOAD_NO_HINTING;
657
658   /* set the base-line based on the string ascent */
659   if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox, utf8))
660     return 0;
661
662   if (!align) {
663     /* this may need adjustment */
664     tx -= bbox[0] * handle->matrix[0] + bbox[5] * handle->matrix[1] + handle->matrix[2];
665     ty += bbox[0] * handle->matrix[3] + bbox[5] * handle->matrix[4] + handle->matrix[5];
666   }
667   while (len) {
668     unsigned long c;
669     if (utf8) {
670       c = i_utf8_advance(&text, &len);
671       if (c == ~0UL) {
672         i_push_error(0, "invalid UTF8 character");
673         return 0;
674       }
675     }
676     else {
677       c = (unsigned char)*text++;
678       --len;
679     }
680     
681     index = FT_Get_Char_Index(handle->face, c);
682     error = FT_Load_Glyph(handle->face, index, loadFlags);
683     if (error) {
684       ft2_push_message(error);
685       i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)", 
686                     c, index);
687       return 0;
688     }
689     slot = handle->face->glyph;
690     gm = &slot->metrics;
691
692     error = FT_Render_Glyph(slot, aa ? ft_render_mode_normal : ft_render_mode_mono);
693     if (error) {
694       ft2_push_message(error);
695       i_push_errorf(0, "rendering glyph 0x%04X (character \\x%02X)");
696       return 0;
697     }
698     if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) {
699       bmp = slot->bitmap.buffer;
700       for (y = 0; y < slot->bitmap.rows; ++y) {
701         int pos = 0;
702         int bit = 0x80;
703         for (x = 0; x < slot->bitmap.width; ++x) {
704           if (bmp[pos] & bit)
705             i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, cl);
706
707           bit >>= 1;
708           if (bit == 0) {
709             bit = 0x80;
710             ++pos;
711           }
712         }
713         bmp += slot->bitmap.pitch;
714       }
715     }
716     else {
717       /* grey scale or something we can treat as greyscale */
718       /* we create a map to convert from the bitmap values to 0-255 */
719       if (last_mode != slot->bitmap.pixel_mode 
720           || last_grays != slot->bitmap.num_grays) {
721         if (!make_bmp_map(&slot->bitmap, map))
722           return 0;
723         last_mode = slot->bitmap.pixel_mode;
724         last_grays = slot->bitmap.num_grays;
725       }
726       
727       bmp = slot->bitmap.buffer;
728       for (y = 0; y < slot->bitmap.rows; ++y) {
729         for (x = 0; x < slot->bitmap.width; ++x) {
730           int value = map[bmp[x]];
731           if (value) {
732             i_gpix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, &pel);
733             for (ch = 0; ch < im->channels; ++ch) {
734               pel.channel[ch] = 
735                 ((255-value)*pel.channel[ch] + value * cl->channel[ch]) / 255;
736             }
737             i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, &pel);
738           }
739         }
740         bmp += slot->bitmap.pitch;
741       }
742     }
743
744     tx += slot->advance.x / 64;
745     ty -= slot->advance.y / 64;
746   }
747
748   return 1;
749 }
750
751 /*
752 =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)
753
754 Renders I<text> to (I<tx>, I<ty>) in I<im> to I<channel> at the given 
755 I<cheight> and I<cwidth>.
756
757 If align is 0, then the text is rendered with the top-left of the
758 first character at (I<tx>, I<ty>).  If align is non-zero then the text
759 is rendered with (I<tx>, I<ty>) aligned with the base-line of the
760 characters.
761
762 If aa is non-zero then the text is anti-aliased.
763
764 Returns non-zero on success.
765
766 =cut
767 */
768
769 i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, int channel,
770          double cheight, double cwidth, char const *text, int len, int align,
771          int aa, int vlayout, int utf8) {
772   int bbox[8];
773   i_img *work;
774   i_color cl, cl2;
775   int x, y;
776
777   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", 
778           handle, im, tx, ty, channel, cheight, cwidth, text, len));
779
780   if (vlayout && !FT_HAS_VERTICAL(handle->face)) {
781     i_push_error(0, "face has no vertical metrics");
782     return 0;
783   }
784
785   if (!i_ft2_bbox_r(handle, cheight, cwidth, text, len, vlayout, utf8, bbox))
786     return 0;
787
788   work = i_img_empty_ch(NULL, bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, 1);
789   cl.channel[0] = 255;
790   if (!i_ft2_text(handle, work, -bbox[0], -bbox[1], &cl, cheight, cwidth, 
791                   text, len, 1, aa, vlayout, utf8))
792     return 0;
793
794   if (!align) {
795     tx -= bbox[4];
796     ty += bbox[5];
797   }
798   
799   /* render to the specified channel */
800   /* this will be sped up ... */
801   for (y = 0; y < work->ysize; ++y) {
802     for (x = 0; x < work->xsize; ++x) {
803       i_gpix(work, x, y, &cl);
804       i_gpix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
805       cl2.channel[channel] = cl.channel[0];
806       i_ppix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
807     }
808   }
809   i_img_destroy(work);
810   return 1;
811 }
812
813 /*
814 =item i_ft2_has_chars(handle, char *text, int len, int utf8, char *out)
815
816 Check if the given characters are defined by the font.
817
818 Returns the number of characters that were checked.
819
820 =cut
821 */
822 int i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, int len, 
823                     int utf8, char *out) {
824   int count = 0;
825   mm_log((1, "i_ft2_has_chars(handle %p, text %p, len %d, utf8 %d)\n", 
826           handle, text, len, utf8));
827
828   while (len) {
829     unsigned long c;
830     int index;
831     if (utf8) {
832       c = i_utf8_advance(&text, &len);
833       if (c == ~0UL) {
834         i_push_error(0, "invalid UTF8 character");
835         return 0;
836       }
837     }
838     else {
839       c = (unsigned char)*text++;
840       --len;
841     }
842     
843     index = FT_Get_Char_Index(handle->face, c);
844     *out++ = index != 0;
845     ++count;
846   }
847
848   return count;
849 }
850
851 /* uses a method described in fterrors.h to build an error translation
852    function
853 */
854 #undef __FTERRORS_H__
855 #define FT_ERRORDEF(e, v, s) case v: i_push_error(code, s); return;
856 #define FT_ERROR_START_LIST 
857 #define FT_ERROR_END_LIST 
858
859 /*
860 =back
861
862 =head2 Internal Functions
863
864 These functions are used in the implementation of freetyp2.c and should not
865 (usually cannot) be called from outside it.
866
867 =over
868
869 =item ft2_push_message(int code)
870
871 Pushes an error message corresponding to code onto the error stack.
872
873 =cut
874 */
875 static void ft2_push_message(int code) {
876   char unknown[40];
877
878   switch (code) {
879 #include FT_ERRORS_H
880   }
881
882   sprintf(unknown, "Unknown Freetype2 error code 0x%04X\n", code);
883   i_push_error(code, unknown);
884 }
885
886 /*
887 =item make_bmp_map(FT_Bitmap *bitmap, unsigned char *map)
888
889 Creates a map to convert grey levels from the glyphs bitmap into
890 values scaled 0..255.
891
892 =cut
893 */
894 static int
895 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map) {
896   int scale;
897   int i;
898
899   switch (bitmap->pixel_mode) {
900   case ft_pixel_mode_grays:
901     scale = bitmap->num_grays;
902     break;
903     
904   default:
905     i_push_errorf(0, "I can't handle pixel mode %d", bitmap->pixel_mode);
906     return 0;
907   }
908
909   /* build the table */
910   for (i = 0; i < scale; ++i)
911     map[i] = i * 255 / (bitmap->num_grays - 1);
912
913   return 1;
914 }
915
916 /* FREETYPE_PATCH was introduced in 2.0.6, we don't want a false 
917    positive on 2.0.0 to 2.0.4, so we accept a false negative in 2.0.5 */
918 #ifndef FREETYPE_PATCH
919 #define FREETYPE_PATCH 4
920 #endif
921
922 /* FT_Get_Postscript_Name() was introduced in FT2.0.5 */
923 #define IM_HAS_FACE_NAME (FREETYPE_MINOR > 0 || FREETYPE_PATCH >= 5)
924 /* #define IM_HAS_FACE_NAME 0 */ 
925
926 /*
927 =item i_ft2_face_name(handle, name_buf, name_buf_size)
928
929 Fills the given buffer with the Postscript Face name of the font,
930 if there is one.
931
932 =cut
933 */
934
935 int
936 i_ft2_face_name(FT2_Fonthandle *handle, char *name_buf, size_t name_buf_size) {
937 #if IM_HAS_FACE_NAME
938   char const *name = FT_Get_Postscript_Name(handle->face);
939
940   i_clear_error();
941
942   if (name) {
943     strncpy(name_buf, name, name_buf_size);
944     name_buf[name_buf_size-1] = '\0';
945
946     return strlen(name) + 1;
947   }
948   else {
949     i_push_error(0, "no face name available");
950     *name_buf = '\0';
951
952     return 0;
953   }
954 #else
955   i_clear_error();
956   i_push_error(0, "Freetype 2.0.6 or later required");
957   *name_buf = '\0';
958
959   return 0;
960 #endif
961 }
962
963 int
964 i_ft2_can_face_name(void) {
965   return IM_HAS_FACE_NAME;
966 }
967
968 /* FT_Has_PS_Glyph_Names() was introduced in FT2.1.1 */
969 /* well, I assume FREETYPE_MAJOR is 2, since we're here */
970 #if FREETYPE_MINOR < 1 || (FREETYPE_MINOR == 1 && FREETYPE_PATCH < 1)
971 #define FT_Has_PS_Glyph_Names(face) (FT_HAS_GLYPH_NAMES(face))
972 #endif
973
974 int
975 i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned long ch, char *name_buf, 
976                  size_t name_buf_size, int reliable_only) {
977 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
978   i_clear_error();
979   *name_buf = '\0';
980   i_push_error(0, "FT2 configured without glyph name support");
981
982   return 0;
983 #else
984   FT_UInt index;
985
986   i_clear_error();
987
988   if (!FT_HAS_GLYPH_NAMES(handle->face)) {
989     i_push_error(0, "no glyph names in font");
990     *name_buf = '\0';
991     return 0;
992   }
993   if (reliable_only && !FT_Has_PS_Glyph_Names(handle->face)) {
994     i_push_error(0, "no reliable glyph names in font - set reliable_only to 0 to try anyway");
995     *name_buf = '\0';
996     return 0;
997   }
998
999   index = FT_Get_Char_Index(handle->face, ch);
1000   
1001   if (index) {
1002     FT_Error error = FT_Get_Glyph_Name(handle->face, index, name_buf, 
1003                                        name_buf_size);
1004     if (error) {
1005       ft2_push_message(error);
1006       *name_buf = '\0';
1007       return;
1008     }
1009     if (*name_buf) {
1010       return strlen(name_buf) + 1;
1011     }
1012     else {
1013       return 0;
1014     }
1015   }
1016   else {
1017     i_push_error(0, "no glyph for that character");
1018     *name_buf = 0;
1019     return 0;
1020   }
1021 #endif
1022 }
1023
1024 int
1025 i_ft2_can_do_glyph_names(void) {
1026 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1027   return 0;
1028 #else
1029   return 1;
1030 #endif
1031 }
1032
1033 int 
1034 i_ft2_face_has_glyph_names(FT2_Fonthandle *handle) {
1035 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1036   return 0;
1037 #else
1038   return FT_Has_PS_Glyph_Names(handle->face);
1039 #endif
1040 }
1041
1042 int
1043 i_ft2_is_multiple_master(FT2_Fonthandle *handle) {
1044   i_clear_error();
1045 #ifdef IM_FT2_MM
1046   return handle->has_mm;
1047 #else
1048   return 0;
1049 #endif
1050 }
1051
1052 int
1053 i_ft2_get_multiple_masters(FT2_Fonthandle *handle, i_font_mm *mm) {
1054 #ifdef IM_FT2_MM
1055   int i;
1056   FT_Multi_Master *mms = &handle->mm;
1057
1058   i_clear_error();
1059   if (!handle->has_mm) {
1060     i_push_error(0, "Font has no multiple masters");
1061     return 0;
1062   }
1063   mm->num_axis = mms->num_axis;
1064   mm->num_designs = mms->num_designs;
1065   for (i = 0; i < mms->num_axis; ++i) {
1066     mm->axis[i].name = mms->axis[i].name;
1067     mm->axis[i].minimum = mms->axis[i].minimum;
1068     mm->axis[i].maximum = mms->axis[i].maximum;
1069   }
1070
1071   return 1;
1072 #else
1073   i_clear_error();
1074   i_push_error(0, "Multiple master functions unavailable");
1075   return 0;
1076 #endif
1077 }
1078
1079 int
1080 i_ft2_set_mm_coords(FT2_Fonthandle *handle, int coord_count, long *coords) {
1081 #ifdef IM_FT2_MM
1082   int i;
1083   FT_Long ftcoords[T1_MAX_MM_AXIS];
1084   FT_Error error;
1085
1086   i_clear_error();
1087   if (!handle->has_mm) {
1088     i_push_error(0, "Font has no multiple masters");
1089     return 0;
1090   }
1091   if (coord_count != handle->mm.num_axis) {
1092     i_push_error(0, "Number of MM coords doesn't match MM axis count");
1093     return 0;
1094   }
1095   for (i = 0; i < coord_count; ++i)
1096     ftcoords[i] = coords[i];
1097
1098   error = FT_Set_MM_Design_Coordinates(handle->face, coord_count, ftcoords);
1099   if (error) {
1100     ft2_push_message(error);
1101     return 0;
1102   }
1103   
1104   return 1;
1105 #else 
1106   i_clear_error();
1107   i_push_error(0, "Multiple master functions unavailable");
1108
1109   return 0;
1110 #endif
1111 }
1112
1113 /*
1114 =back
1115
1116 =head1 AUTHOR
1117
1118 Tony Cook <tony@develop-help.com>, with a fair amount of help from
1119 reading the code in font.c.
1120
1121 =head1 SEE ALSO
1122
1123 font.c, Imager::Font(3), Imager(3)
1124
1125 http://www.freetype.org/
1126
1127 =cut
1128 */
1129