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;
645 int loadFlags = FT_LOAD_DEFAULT;
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));
652 if (!FT_HAS_VERTICAL(handle->face)) {
653 i_push_error(0, "face has no vertical metrics");
656 loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
659 loadFlags |= FT_LOAD_NO_HINTING;
661 /* set the base-line based on the string ascent */
662 if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox, utf8))
666 i_render_init(&render, im, bbox[BBOX_POS_WIDTH] - bbox[BBOX_NEG_WIDTH]);
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];
676 c = i_utf8_advance(&text, &len);
678 i_push_error(0, "invalid UTF8 character");
683 c = (unsigned char)*text++;
687 index = FT_Get_Char_Index(handle->face, c);
688 error = FT_Load_Glyph(handle->face, index, loadFlags);
690 ft2_push_message(error);
691 i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)",
694 i_render_done(&render);
697 slot = handle->face->glyph;
701 error = FT_Render_Glyph(slot, aa ? ft_render_mode_normal : ft_render_mode_mono);
703 ft2_push_message(error);
704 i_push_errorf(0, "rendering glyph 0x%04X (character \\x%02X)");
706 i_render_done(&render);
709 if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) {
710 bmp = slot->bitmap.buffer;
711 for (y = 0; y < slot->bitmap.rows; ++y) {
714 for (x = 0; x < slot->bitmap.width; ++x) {
716 i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, cl);
724 bmp += slot->bitmap.pitch;
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))
734 last_mode = slot->bitmap.pixel_mode;
735 last_grays = slot->bitmap.num_grays;
738 bmp = slot->bitmap.buffer;
739 for (y = 0; y < slot->bitmap.rows; ++y) {
740 if (last_mode == ft_pixel_mode_grays &&
742 for (x = 0; x < slot->bitmap.width; ++x)
743 bmp[x] = map[bmp[x]];
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;
752 tx += slot->advance.x / 64;
753 ty -= slot->advance.y / 64;
757 i_render_done(&render);
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)
765 Renders I<text> to (I<tx>, I<ty>) in I<im> to I<channel> at the given
766 I<cheight> and I<cwidth>.
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
773 If aa is non-zero then the text is anti-aliased.
775 Returns non-zero on success.
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) {
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));
792 if (vlayout && !FT_HAS_VERTICAL(handle->face)) {
793 i_push_error(0, "face has no vertical metrics");
797 if (!i_ft2_bbox_r(handle, cheight, cwidth, text, len, vlayout, utf8, bbox))
800 work = i_img_empty_ch(NULL, bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, 1);
802 if (!i_ft2_text(handle, work, -bbox[0], -bbox[1], &cl, cheight, cwidth,
803 text, len, 1, aa, vlayout, utf8))
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);
826 =item i_ft2_has_chars(handle, char *text, int len, int utf8, char *out)
828 Check if the given characters are defined by the font.
830 Returns the number of characters that were checked.
834 int i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, int len,
835 int utf8, char *out) {
837 mm_log((1, "i_ft2_has_chars(handle %p, text %p, len %d, utf8 %d)\n",
838 handle, text, len, utf8));
844 c = i_utf8_advance(&text, &len);
846 i_push_error(0, "invalid UTF8 character");
851 c = (unsigned char)*text++;
855 index = FT_Get_Char_Index(handle->face, c);
863 /* uses a method described in fterrors.h to build an error translation
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
874 =head2 Internal Functions
876 These functions are used in the implementation of freetyp2.c and should not
877 (usually cannot) be called from outside it.
881 =item ft2_push_message(int code)
883 Pushes an error message corresponding to code onto the error stack.
887 static void ft2_push_message(int code) {
894 sprintf(unknown, "Unknown Freetype2 error code 0x%04X\n", code);
895 i_push_error(code, unknown);
899 =item make_bmp_map(FT_Bitmap *bitmap, unsigned char *map)
901 Creates a map to convert grey levels from the glyphs bitmap into
902 values scaled 0..255.
907 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map) {
911 switch (bitmap->pixel_mode) {
912 case ft_pixel_mode_grays:
913 scale = bitmap->num_grays;
917 i_push_errorf(0, "I can't handle pixel mode %d", bitmap->pixel_mode);
921 /* build the table */
922 for (i = 0; i < scale; ++i)
923 map[i] = i * 255 / (bitmap->num_grays - 1);
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
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 */
939 =item i_ft2_face_name(handle, name_buf, name_buf_size)
941 Fills the given buffer with the Postscript Face name of the font,
948 i_ft2_face_name(FT2_Fonthandle *handle, char *name_buf, size_t name_buf_size) {
950 char const *name = FT_Get_Postscript_Name(handle->face);
955 strncpy(name_buf, name, name_buf_size);
956 name_buf[name_buf_size-1] = '\0';
958 return strlen(name) + 1;
961 i_push_error(0, "no face name available");
968 i_push_error(0, "Freetype 2.0.6 or later required");
976 i_ft2_can_face_name(void) {
977 return IM_HAS_FACE_NAME;
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))
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
992 i_push_error(0, "FT2 configured without glyph name support");
1000 if (!FT_HAS_GLYPH_NAMES(handle->face)) {
1001 i_push_error(0, "no glyph names in font");
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");
1011 index = FT_Get_Char_Index(handle->face, ch);
1014 FT_Error error = FT_Get_Glyph_Name(handle->face, index, name_buf,
1017 ft2_push_message(error);
1022 return strlen(name_buf) + 1;
1029 i_push_error(0, "no glyph for that character");
1037 i_ft2_can_do_glyph_names(void) {
1038 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1046 i_ft2_face_has_glyph_names(FT2_Fonthandle *handle) {
1047 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1050 return FT_Has_PS_Glyph_Names(handle->face);
1055 i_ft2_is_multiple_master(FT2_Fonthandle *handle) {
1058 return handle->has_mm;
1065 i_ft2_get_multiple_masters(FT2_Fonthandle *handle, i_font_mm *mm) {
1068 FT_Multi_Master *mms = &handle->mm;
1071 if (!handle->has_mm) {
1072 i_push_error(0, "Font has no multiple masters");
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;
1086 i_push_error(0, "Multiple master functions unavailable");
1092 i_ft2_set_mm_coords(FT2_Fonthandle *handle, int coord_count, const long *coords) {
1095 FT_Long ftcoords[T1_MAX_MM_AXIS];
1099 if (!handle->has_mm) {
1100 i_push_error(0, "Font has no multiple masters");
1103 if (coord_count != handle->mm.num_axis) {
1104 i_push_error(0, "Number of MM coords doesn't match MM axis count");
1107 for (i = 0; i < coord_count; ++i)
1108 ftcoords[i] = coords[i];
1110 error = FT_Set_MM_Design_Coordinates(handle->face, coord_count, ftcoords);
1112 ft2_push_message(error);
1119 i_push_error(0, "Multiple master functions unavailable");
1130 Tony Cook <tony@develop-help.com>, with a fair amount of help from
1131 reading the code in font.c.
1135 font.c, Imager::Font(3), Imager(3)
1137 http://www.freetype.org/