4 freetyp2.c - font support via the FreeType library version 2.
8 if (!i_ft2_init()) { error }
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 }
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 }
19 if (!i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, length, align,
21 if (!i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, length,
27 Implements Imager font support using the FreeType2 library.
29 The FreeType2 library understands several font file types, including
30 Truetype, Type1 and Windows FNT.
40 #include FT_FREETYPE_H
41 #ifdef FT_MULTIPLE_MASTERS_H
42 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
44 #include FT_MULTIPLE_MASTERS_H
48 static void ft2_push_message(int code);
50 static FT_Library library;
53 =item i_ft2_init(void)
55 Initializes the Freetype 2 library.
57 Returns true on success, false on failure.
66 error = FT_Init_FreeType(&library);
68 ft2_push_message(error);
69 i_push_error(0, "Initializing Freetype2");
75 struct FT2_Fonthandle {
81 /* used to adjust so we can align the draw point to the top-left */
85 /* Multiple master data if any */
91 /* the following is used to select a "best" encoding */
92 static struct enc_score {
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 },
113 =item i_ft2_new(char *name, int index)
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
119 Return NULL on failure.
125 i_ft2_new(const char *name, int index) {
127 FT2_Fonthandle *result;
130 FT_Encoding encoding;
133 mm_log((1, "i_ft2_new(name %p, index %d)\n", name, index));
136 error = FT_New_Face(library, name, index, &face);
138 ft2_push_message(error);
139 i_push_error(error, "Opening face");
140 mm_log((2, "error opening face '%s': %d\n", name, error));
144 encoding = face->num_charmaps ? face->charmaps[0]->encoding : ft_encoding_unicode;
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;
159 FT_Select_Charmap(face, encoding);
160 mm_log((2, "i_ft2_new, selected encoding %lX\n", encoding));
162 result = mymalloc(sizeof(FT2_Fonthandle));
164 result->xdpi = result->ydpi = 72;
165 result->encoding = encoding;
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.
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;
181 FT_Multi_Master *mm = &result->mm;
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)));
194 mm_log((2, "No multiple masters\n"));
204 =item i_ft2_destroy(FT2_Fonthandle *handle)
206 Destroys a font object, which must have been the return value of
212 i_ft2_destroy(FT2_Fonthandle *handle) {
213 FT_Done_Face(handle->face);
218 =item i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi)
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.
223 Both xdpi and ydpi should be positive.
225 Return true on success.
230 i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi) {
232 if (xdpi > 0 && ydpi > 0) {
238 i_push_error(0, "resolutions must be positive");
244 =item i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi)
246 Retrieves the current horizontal and vertical resolutions at which
247 point sizes are scaled.
252 i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi) {
253 *xdpi = handle->xdpi;
254 *ydpi = handle->ydpi;
260 =item i_ft2_settransform(FT2_FontHandle *handle, double *matrix)
262 Sets a transormation matrix for output.
264 This should be a 2 x 3 matrix like:
266 matrix[0] matrix[1] matrix[2]
267 matrix[3] matrix[4] matrix[5]
272 i_ft2_settransform(FT2_Fonthandle *handle, const double *matrix) {
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 */
284 FT_Set_Transform(handle->face, &m, &v);
286 for (i = 0; i < 6; ++i)
287 handle->matrix[i] = matrix[i];
294 =item i_ft2_sethinting(FT2_Fonthandle *handle, int hinting)
296 If hinting is non-zero then glyph hinting is enabled, otherwise disabled.
298 i_ft2_settransform() disables hinting to prevent distortions in
299 gradual text transformations.
303 int i_ft2_sethinting(FT2_Fonthandle *handle, int hinting) {
304 handle->hint = hinting;
309 =item i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, int len, int *bbox)
311 Retrieves bounding box information for the font at the given
312 character width and height. This ignores the transformation matrix.
314 Returns non-zero on success.
319 i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth,
320 char const *text, int len, int *bbox, int utf8) {
325 int ascent = 0, descent = 0;
326 int glyph_ascent, glyph_descent;
327 FT_Glyph_Metrics *gm;
329 int loadFlags = FT_LOAD_DEFAULT;
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));
335 error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64,
336 handle->xdpi, handle->ydpi);
338 ft2_push_message(error);
339 i_push_error(0, "setting size");
343 loadFlags |= FT_LOAD_NO_HINTING;
350 c = i_utf8_advance(&text, &len);
352 i_push_error(0, "invalid UTF8 character");
357 c = (unsigned char)*text++;
361 index = FT_Get_Char_Index(handle->face, c);
362 error = FT_Load_Glyph(handle->face, index, loadFlags);
364 ft2_push_message(error);
365 i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)",
369 gm = &handle->face->glyph->metrics;
370 glyph_ascent = gm->horiBearingY / 64;
371 glyph_descent = glyph_ascent - gm->height/64;
373 start = gm->horiBearingX / 64;
374 /* handles -ve values properly */
375 ascent = glyph_ascent;
376 descent = glyph_descent;
380 if (glyph_ascent > ascent)
381 ascent = glyph_ascent;
382 if (glyph_descent < descent)
383 descent = glyph_descent;
385 width += gm->horiAdvance / 64;
389 handle the case where the right the of the character overlaps the
391 rightb = (gm->horiAdvance - gm->horiBearingX - gm->width)/64;
397 bbox[BBOX_NEG_WIDTH] = start;
398 bbox[BBOX_GLOBAL_DESCENT] = handle->face->size->metrics.descender / 64;
399 bbox[BBOX_POS_WIDTH] = width;
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]));
409 return BBOX_RIGHT_BEARING + 1;
413 =item transform_box(FT2_FontHandle *handle, int bbox[4])
415 bbox contains coorinates of a the top-left and bottom-right of a bounding
416 box relative to a point.
418 This is then transformed and the values in bbox[4] are the top-left
419 and bottom-right of the new bounding box.
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
430 void ft2_transform_box(FT2_Fonthandle *handle, int bbox[4]) {
432 double *matrix = handle->matrix;
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];
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])));
450 =item expand_bounds(int bbox[4], int bbox2[4])
452 Treating bbox[] and bbox2[] as 2 bounding boxes, produces a new
453 bounding box in bbox[] that encloses both.
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]);
465 =item i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, int len, int vlayout, int utf8, int *bbox)
467 Retrieves bounding box information for the font at the given
468 character width and height.
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.
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
480 Returns non-zero on success.
485 i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth,
486 char const *text, int len, int vlayout, int utf8, int *bbox) {
491 int ascent = 0, descent = 0;
492 int glyph_ascent, glyph_descent;
493 FT_Glyph_Metrics *gm;
499 int loadFlags = FT_LOAD_DEFAULT;
502 loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
504 loadFlags |= FT_LOAD_NO_HINTING;
506 error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64,
507 handle->xdpi, handle->ydpi);
509 ft2_push_message(error);
510 i_push_error(0, "setting size");
518 c = i_utf8_advance(&text, &len);
520 i_push_error(0, "invalid UTF8 character");
525 c = (unsigned char)*text++;
529 index = FT_Get_Char_Index(handle->face, c);
530 error = FT_Load_Glyph(handle->face, index, loadFlags);
532 ft2_push_message(error);
533 i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)",
537 slot = handle->face->glyph;
540 /* these probably don't mean much for vertical layouts */
541 glyph_ascent = gm->horiBearingY / 64;
542 glyph_descent = glyph_ascent - gm->height/64;
544 work[0] = gm->vertBearingX;
545 work[1] = gm->vertBearingY;
548 work[0] = gm->horiBearingX;
549 work[1] = gm->horiBearingY;
551 work[2] = gm->width + work[0];
552 work[3] = work[1] - gm->height;
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;
559 ft2_transform_box(handle, work);
560 for (i = 0; i < 4; ++i)
567 for (i = 0; i < 4; ++i)
569 ascent = glyph_ascent;
570 descent = glyph_descent;
574 expand_bounds(bounds, work);
576 x += slot->advance.x / 64;
577 y += slot->advance.y / 64;
579 if (glyph_ascent > ascent)
580 ascent = glyph_ascent;
581 if (glyph_descent > descent)
582 descent = glyph_descent;
586 handle the case where the right the of the character overlaps the
588 /*int rightb = gm->horiAdvance - gm->horiBearingX - gm->width;
590 width -= rightb / 64;*/
594 /* at this point bounds contains the bounds relative to the CP,
595 and x, y hold the final position relative to the CP */
602 bbox[1] = -bounds[3];
604 bbox[3] = -bounds[1];
612 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map);
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)
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>.
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
625 If aa is non-zero then the text is anti-aliased.
627 Returns non-zero on success.
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) {
637 FT_Glyph_Metrics *gm;
638 int bbox[BOUNDING_BOX_COUNT];
642 unsigned char map[256];
643 char last_mode = ft_pixel_mode_none;
647 int loadFlags = FT_LOAD_DEFAULT;
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));
654 if (!FT_HAS_VERTICAL(handle->face)) {
655 i_push_error(0, "face has no vertical metrics");
658 loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
661 loadFlags |= FT_LOAD_NO_HINTING;
663 /* set the base-line based on the string ascent */
664 if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox, utf8))
668 i_render_init(&render, im, bbox[BBOX_POS_WIDTH] - bbox[BBOX_NEG_WIDTH]);
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];
678 c = i_utf8_advance(&text, &len);
680 i_push_error(0, "invalid UTF8 character");
685 c = (unsigned char)*text++;
689 index = FT_Get_Char_Index(handle->face, c);
690 error = FT_Load_Glyph(handle->face, index, loadFlags);
692 ft2_push_message(error);
693 i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)",
696 i_render_done(&render);
699 slot = handle->face->glyph;
703 error = FT_Render_Glyph(slot, aa ? ft_render_mode_normal : ft_render_mode_mono);
705 ft2_push_message(error);
706 i_push_errorf(0, "rendering glyph 0x%04X (character \\x%02X)");
708 i_render_done(&render);
711 if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) {
712 bmp = slot->bitmap.buffer;
713 for (y = 0; y < slot->bitmap.rows; ++y) {
716 for (x = 0; x < slot->bitmap.width; ++x) {
718 i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, cl);
726 bmp += slot->bitmap.pitch;
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))
736 last_mode = slot->bitmap.pixel_mode;
737 last_grays = slot->bitmap.num_grays;
740 bmp = slot->bitmap.buffer;
741 for (y = 0; y < slot->bitmap.rows; ++y) {
742 if (last_mode == ft_pixel_mode_grays &&
744 for (x = 0; x < slot->bitmap.width; ++x)
745 bmp[x] = map[bmp[x]];
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;
754 tx += slot->advance.x / 64;
755 ty -= slot->advance.y / 64;
759 i_render_done(&render);
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)
767 Renders I<text> to (I<tx>, I<ty>) in I<im> to I<channel> at the given
768 I<cheight> and I<cwidth>.
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
775 If aa is non-zero then the text is anti-aliased.
777 Returns non-zero on success.
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) {
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));
794 if (vlayout && !FT_HAS_VERTICAL(handle->face)) {
795 i_push_error(0, "face has no vertical metrics");
799 if (!i_ft2_bbox_r(handle, cheight, cwidth, text, len, vlayout, utf8, bbox))
802 work = i_img_empty_ch(NULL, bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, 1);
804 if (!i_ft2_text(handle, work, -bbox[0], -bbox[1], &cl, cheight, cwidth,
805 text, len, 1, aa, vlayout, utf8))
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);
828 =item i_ft2_has_chars(handle, char *text, int len, int utf8, char *out)
830 Check if the given characters are defined by the font.
832 Returns the number of characters that were checked.
836 int i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, int len,
837 int utf8, char *out) {
839 mm_log((1, "i_ft2_has_chars(handle %p, text %p, len %d, utf8 %d)\n",
840 handle, text, len, utf8));
846 c = i_utf8_advance(&text, &len);
848 i_push_error(0, "invalid UTF8 character");
853 c = (unsigned char)*text++;
857 index = FT_Get_Char_Index(handle->face, c);
865 /* uses a method described in fterrors.h to build an error translation
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
876 =head2 Internal Functions
878 These functions are used in the implementation of freetyp2.c and should not
879 (usually cannot) be called from outside it.
883 =item ft2_push_message(int code)
885 Pushes an error message corresponding to code onto the error stack.
889 static void ft2_push_message(int code) {
896 sprintf(unknown, "Unknown Freetype2 error code 0x%04X\n", code);
897 i_push_error(code, unknown);
901 =item make_bmp_map(FT_Bitmap *bitmap, unsigned char *map)
903 Creates a map to convert grey levels from the glyphs bitmap into
904 values scaled 0..255.
909 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map) {
913 switch (bitmap->pixel_mode) {
914 case ft_pixel_mode_grays:
915 scale = bitmap->num_grays;
919 i_push_errorf(0, "I can't handle pixel mode %d", bitmap->pixel_mode);
923 /* build the table */
924 for (i = 0; i < scale; ++i)
925 map[i] = i * 255 / (bitmap->num_grays - 1);
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
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 */
941 =item i_ft2_face_name(handle, name_buf, name_buf_size)
943 Fills the given buffer with the Postscript Face name of the font,
950 i_ft2_face_name(FT2_Fonthandle *handle, char *name_buf, size_t name_buf_size) {
952 char const *name = FT_Get_Postscript_Name(handle->face);
957 strncpy(name_buf, name, name_buf_size);
958 name_buf[name_buf_size-1] = '\0';
960 return strlen(name) + 1;
963 i_push_error(0, "no face name available");
970 i_push_error(0, "Freetype 2.0.6 or later required");
978 i_ft2_can_face_name(void) {
979 return IM_HAS_FACE_NAME;
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))
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
994 i_push_error(0, "FT2 configured without glyph name support");
1002 if (!FT_HAS_GLYPH_NAMES(handle->face)) {
1003 i_push_error(0, "no glyph names in font");
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");
1013 index = FT_Get_Char_Index(handle->face, ch);
1016 FT_Error error = FT_Get_Glyph_Name(handle->face, index, name_buf,
1019 ft2_push_message(error);
1024 return strlen(name_buf) + 1;
1031 i_push_error(0, "no glyph for that character");
1039 i_ft2_can_do_glyph_names(void) {
1040 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1048 i_ft2_face_has_glyph_names(FT2_Fonthandle *handle) {
1049 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1052 return FT_Has_PS_Glyph_Names(handle->face);
1057 i_ft2_is_multiple_master(FT2_Fonthandle *handle) {
1060 return handle->has_mm;
1067 i_ft2_get_multiple_masters(FT2_Fonthandle *handle, i_font_mm *mm) {
1070 FT_Multi_Master *mms = &handle->mm;
1073 if (!handle->has_mm) {
1074 i_push_error(0, "Font has no multiple masters");
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;
1088 i_push_error(0, "Multiple master functions unavailable");
1094 i_ft2_set_mm_coords(FT2_Fonthandle *handle, int coord_count, const long *coords) {
1097 FT_Long ftcoords[T1_MAX_MM_AXIS];
1101 if (!handle->has_mm) {
1102 i_push_error(0, "Font has no multiple masters");
1105 if (coord_count != handle->mm.num_axis) {
1106 i_push_error(0, "Number of MM coords doesn't match MM axis count");
1109 for (i = 0; i < coord_count; ++i)
1110 ftcoords[i] = coords[i];
1112 error = FT_Set_MM_Design_Coordinates(handle->face, coord_count, ftcoords);
1114 ft2_push_message(error);
1121 i_push_error(0, "Multiple master functions unavailable");
1132 Tony Cook <tony@develop-help.com>, with a fair amount of help from
1133 reading the code in font.c.
1137 font.c, Imager::Font(3), Imager(3)
1139 http://www.freetype.org/