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 int ft2_initialized = 0;
51 static FT_Library library;
54 =item i_ft2_init(void)
56 Initializes the Freetype 2 library.
58 Returns true on success, false on failure.
67 error = FT_Init_FreeType(&library);
69 ft2_push_message(error);
70 i_push_error(0, "Initializing Freetype2");
79 struct FT2_Fonthandle {
85 /* used to adjust so we can align the draw point to the top-left */
89 /* Multiple master data if any */
95 /* the following is used to select a "best" encoding */
96 static struct enc_score {
101 /* the selections here are fairly arbitrary
102 ideally we need to give the user a list of encodings available
103 and a mechanism to choose one */
104 { ft_encoding_unicode, 10 },
105 { ft_encoding_sjis, 8 },
106 { ft_encoding_gb2312, 8 },
107 { ft_encoding_big5, 8 },
108 { ft_encoding_wansung, 8 },
109 { ft_encoding_johab, 8 },
110 { ft_encoding_latin_2, 6 },
111 { ft_encoding_apple_roman, 6 },
112 { ft_encoding_adobe_standard, 6 },
113 { ft_encoding_adobe_expert, 6 },
117 =item i_ft2_new(char *name, int index)
119 Creates a new font object, from the file given by I<name>. I<index>
120 is the index of the font in a file with multiple fonts, where 0 is the
123 Return NULL on failure.
129 i_ft2_new(const char *name, int index) {
131 FT2_Fonthandle *result;
134 FT_Encoding encoding;
137 mm_log((1, "i_ft2_new(name %p, index %d)\n", name, index));
139 if (!ft2_initialized && !i_ft2_init())
143 error = FT_New_Face(library, name, index, &face);
145 ft2_push_message(error);
146 i_push_error(error, "Opening face");
147 mm_log((2, "error opening face '%s': %d\n", name, error));
151 encoding = face->num_charmaps ? face->charmaps[0]->encoding : ft_encoding_unicode;
153 for (i = 0; i < face->num_charmaps; ++i) {
154 FT_Encoding enc_entry = face->charmaps[i]->encoding;
155 mm_log((2, "i_ft2_new, encoding %lX platform %u encoding %u\n",
156 enc_entry, face->charmaps[i]->platform_id,
157 face->charmaps[i]->encoding_id));
158 for (j = 0; j < sizeof(enc_scores) / sizeof(*enc_scores); ++j) {
159 if (enc_scores[j].encoding == enc_entry && enc_scores[j].score > score) {
160 encoding = enc_entry;
161 score = enc_scores[j].score;
166 FT_Select_Charmap(face, encoding);
167 mm_log((2, "i_ft2_new, selected encoding %lX\n", encoding));
169 result = mymalloc(sizeof(FT2_Fonthandle));
171 result->xdpi = result->ydpi = 72;
172 result->encoding = encoding;
174 /* by default we disable hinting on a call to i_ft2_settransform()
175 if we don't do this, then the hinting can the untransformed text
176 to be a different size to the transformed text.
177 Obviously we have it initially enabled.
181 /* I originally forgot this: :/ */
182 /*i_ft2_settransform(result, matrix); */
183 result->matrix[0] = 1; result->matrix[1] = 0; result->matrix[2] = 0;
184 result->matrix[3] = 0; result->matrix[4] = 1; result->matrix[5] = 0;
188 FT_Multi_Master *mm = &result->mm;
191 if ((face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) != 0
192 && (error = FT_Get_Multi_Master(face, mm)) == 0) {
193 mm_log((2, "MM Font, %d axes, %d designs\n", mm->num_axis, mm->num_designs));
194 for (i = 0; i < mm->num_axis; ++i) {
195 mm_log((2, " axis %d name %s range %ld - %ld\n", i, mm->axis[i].name,
196 (long)(mm->axis[i].minimum), (long)(mm->axis[i].maximum)));
201 mm_log((2, "No multiple masters\n"));
211 =item i_ft2_destroy(FT2_Fonthandle *handle)
213 Destroys a font object, which must have been the return value of
219 i_ft2_destroy(FT2_Fonthandle *handle) {
220 FT_Done_Face(handle->face);
225 =item i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi)
227 Sets the resolution in dots per inch at which point sizes scaled, by
228 default xdpi and ydpi are 72, so that 1 point maps to 1 pixel.
230 Both xdpi and ydpi should be positive.
232 Return true on success.
237 i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi) {
239 if (xdpi > 0 && ydpi > 0) {
245 i_push_error(0, "resolutions must be positive");
251 =item i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi)
253 Retrieves the current horizontal and vertical resolutions at which
254 point sizes are scaled.
259 i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi) {
260 *xdpi = handle->xdpi;
261 *ydpi = handle->ydpi;
267 =item i_ft2_settransform(FT2_FontHandle *handle, double *matrix)
269 Sets a transormation matrix for output.
271 This should be a 2 x 3 matrix like:
273 matrix[0] matrix[1] matrix[2]
274 matrix[3] matrix[4] matrix[5]
279 i_ft2_settransform(FT2_Fonthandle *handle, const double *matrix) {
284 m.xx = matrix[0] * 65536;
285 m.xy = matrix[1] * 65536;
286 v.x = matrix[2]; /* this could be pels of 26.6 fixed - not sure */
287 m.yx = matrix[3] * 65536;
288 m.yy = matrix[4] * 65536;
289 v.y = matrix[5]; /* see just above */
291 FT_Set_Transform(handle->face, &m, &v);
293 for (i = 0; i < 6; ++i)
294 handle->matrix[i] = matrix[i];
301 =item i_ft2_sethinting(FT2_Fonthandle *handle, int hinting)
303 If hinting is non-zero then glyph hinting is enabled, otherwise disabled.
305 i_ft2_settransform() disables hinting to prevent distortions in
306 gradual text transformations.
310 int i_ft2_sethinting(FT2_Fonthandle *handle, int hinting) {
311 handle->hint = hinting;
316 =item i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, int len, int *bbox)
318 Retrieves bounding box information for the font at the given
319 character width and height. This ignores the transformation matrix.
321 Returns non-zero on success.
326 i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth,
327 char const *text, int len, int *bbox, int utf8) {
332 int ascent = 0, descent = 0;
333 int glyph_ascent, glyph_descent;
334 FT_Glyph_Metrics *gm;
336 int loadFlags = FT_LOAD_DEFAULT;
339 mm_log((1, "i_ft2_bbox(handle %p, cheight %f, cwidth %f, text %p, len %d, bbox %p)\n",
340 handle, cheight, cwidth, text, len, bbox));
342 error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64,
343 handle->xdpi, handle->ydpi);
345 ft2_push_message(error);
346 i_push_error(0, "setting size");
350 loadFlags |= FT_LOAD_NO_HINTING;
357 c = i_utf8_advance(&text, &len);
359 i_push_error(0, "invalid UTF8 character");
364 c = (unsigned char)*text++;
368 index = FT_Get_Char_Index(handle->face, c);
369 error = FT_Load_Glyph(handle->face, index, loadFlags);
371 ft2_push_message(error);
372 i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)",
376 gm = &handle->face->glyph->metrics;
377 glyph_ascent = gm->horiBearingY / 64;
378 glyph_descent = glyph_ascent - gm->height/64;
380 start = gm->horiBearingX / 64;
381 /* handles -ve values properly */
382 ascent = glyph_ascent;
383 descent = glyph_descent;
387 if (glyph_ascent > ascent)
388 ascent = glyph_ascent;
389 if (glyph_descent < descent)
390 descent = glyph_descent;
392 width += gm->horiAdvance / 64;
396 handle the case where the right the of the character overlaps the
398 rightb = (gm->horiAdvance - gm->horiBearingX - gm->width)/64;
404 bbox[BBOX_NEG_WIDTH] = start;
405 bbox[BBOX_GLOBAL_DESCENT] = handle->face->size->metrics.descender / 64;
406 bbox[BBOX_POS_WIDTH] = width;
408 bbox[BBOX_POS_WIDTH] -= rightb;
409 bbox[BBOX_GLOBAL_ASCENT] = handle->face->size->metrics.ascender / 64;
410 bbox[BBOX_DESCENT] = descent;
411 bbox[BBOX_ASCENT] = ascent;
412 bbox[BBOX_ADVANCE_WIDTH] = width;
413 bbox[BBOX_RIGHT_BEARING] = rightb;
414 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]));
416 return BBOX_RIGHT_BEARING + 1;
420 =item transform_box(FT2_FontHandle *handle, int bbox[4])
422 bbox contains coorinates of a the top-left and bottom-right of a bounding
423 box relative to a point.
425 This is then transformed and the values in bbox[4] are the top-left
426 and bottom-right of the new bounding box.
428 This is meant to provide the bounding box of a transformed character
429 box. The problem is that if the character was round and is rotated,
430 the real bounding box isn't going to be much different from the
431 original, but this function will return a _bigger_ bounding box. I
432 suppose I could work my way through the glyph outline, but that's
437 void ft2_transform_box(FT2_Fonthandle *handle, int bbox[4]) {
439 double *matrix = handle->matrix;
441 work[0] = matrix[0] * bbox[0] + matrix[1] * bbox[1];
442 work[1] = matrix[3] * bbox[0] + matrix[4] * bbox[1];
443 work[2] = matrix[0] * bbox[2] + matrix[1] * bbox[1];
444 work[3] = matrix[3] * bbox[2] + matrix[4] * bbox[1];
445 work[4] = matrix[0] * bbox[0] + matrix[1] * bbox[3];
446 work[5] = matrix[3] * bbox[0] + matrix[4] * bbox[3];
447 work[6] = matrix[0] * bbox[2] + matrix[1] * bbox[3];
448 work[7] = matrix[3] * bbox[2] + matrix[4] * bbox[3];
450 bbox[0] = floor(i_min(i_min(work[0], work[2]),i_min(work[4], work[6])));
451 bbox[1] = floor(i_min(i_min(work[1], work[3]),i_min(work[5], work[7])));
452 bbox[2] = ceil(i_max(i_max(work[0], work[2]),i_max(work[4], work[6])));
453 bbox[3] = ceil(i_max(i_max(work[1], work[3]),i_max(work[5], work[7])));
457 =item expand_bounds(int bbox[4], int bbox2[4])
459 Treating bbox[] and bbox2[] as 2 bounding boxes, produces a new
460 bounding box in bbox[] that encloses both.
464 static void expand_bounds(int bbox[4], int bbox2[4]) {
465 bbox[0] = i_min(bbox[0], bbox2[0]);
466 bbox[1] = i_min(bbox[1], bbox2[1]);
467 bbox[2] = i_max(bbox[2], bbox2[2]);
468 bbox[3] = i_max(bbox[3], bbox2[3]);
472 =item i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, int len, int vlayout, int utf8, int *bbox)
474 Retrieves bounding box information for the font at the given
475 character width and height.
477 This version finds the rectangular bounding box of the glyphs, with
478 the text as transformed by the transformation matrix. As with
479 i_ft2_bbox (bbox[0], bbox[1]) will the the offset from the start of
480 the topline to the top-left of the bounding box. Unlike i_ft2_bbox()
481 this could be near the bottom left corner of the box.
483 (bbox[4], bbox[5]) is the offset to the start of the baseline.
484 (bbox[6], bbox[7]) is the offset from the start of the baseline to the
487 Returns non-zero on success.
492 i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth,
493 char const *text, int len, int vlayout, int utf8, int *bbox) {
498 int ascent = 0, descent = 0;
499 int glyph_ascent, glyph_descent;
500 FT_Glyph_Metrics *gm;
506 int loadFlags = FT_LOAD_DEFAULT;
509 loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
511 loadFlags |= FT_LOAD_NO_HINTING;
513 error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64,
514 handle->xdpi, handle->ydpi);
516 ft2_push_message(error);
517 i_push_error(0, "setting size");
525 c = i_utf8_advance(&text, &len);
527 i_push_error(0, "invalid UTF8 character");
532 c = (unsigned char)*text++;
536 index = FT_Get_Char_Index(handle->face, c);
537 error = FT_Load_Glyph(handle->face, index, loadFlags);
539 ft2_push_message(error);
540 i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)",
544 slot = handle->face->glyph;
547 /* these probably don't mean much for vertical layouts */
548 glyph_ascent = gm->horiBearingY / 64;
549 glyph_descent = glyph_ascent - gm->height/64;
551 work[0] = gm->vertBearingX;
552 work[1] = gm->vertBearingY;
555 work[0] = gm->horiBearingX;
556 work[1] = gm->horiBearingY;
558 work[2] = gm->width + work[0];
559 work[3] = work[1] - gm->height;
561 bbox[4] = work[0] * handle->matrix[0] + work[1] * handle->matrix[1] + handle->matrix[2];
562 bbox[5] = work[0] * handle->matrix[3] + work[1] * handle->matrix[4] + handle->matrix[5];
563 bbox[4] = bbox[4] < 0 ? -(-bbox[4] + 32)/64 : (bbox[4] + 32) / 64;
566 ft2_transform_box(handle, work);
567 for (i = 0; i < 4; ++i)
574 for (i = 0; i < 4; ++i)
576 ascent = glyph_ascent;
577 descent = glyph_descent;
581 expand_bounds(bounds, work);
583 x += slot->advance.x / 64;
584 y += slot->advance.y / 64;
586 if (glyph_ascent > ascent)
587 ascent = glyph_ascent;
588 if (glyph_descent > descent)
589 descent = glyph_descent;
593 handle the case where the right the of the character overlaps the
595 /*int rightb = gm->horiAdvance - gm->horiBearingX - gm->width;
597 width -= rightb / 64;*/
601 /* at this point bounds contains the bounds relative to the CP,
602 and x, y hold the final position relative to the CP */
609 bbox[1] = -bounds[3];
611 bbox[3] = -bounds[1];
619 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map);
622 =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)
624 Renders I<text> to (I<tx>, I<ty>) in I<im> using color I<cl> at the given
625 I<cheight> and I<cwidth>.
627 If align is 0, then the text is rendered with the top-left of the
628 first character at (I<tx>, I<ty>). If align is non-zero then the text
629 is rendered with (I<tx>, I<ty>) aligned with the base-line of the
632 If aa is non-zero then the text is anti-aliased.
634 Returns non-zero on success.
639 i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, const i_color *cl,
640 double cheight, double cwidth, char const *text, int len, int align,
641 int aa, int vlayout, int utf8) {
644 FT_Glyph_Metrics *gm;
645 int bbox[BOUNDING_BOX_COUNT];
649 unsigned char map[256];
650 char last_mode = ft_pixel_mode_none;
652 int loadFlags = FT_LOAD_DEFAULT;
655 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",
656 handle, im, tx, ty, cl, cheight, cwidth, text, align, aa));
659 if (!FT_HAS_VERTICAL(handle->face)) {
660 i_push_error(0, "face has no vertical metrics");
663 loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
666 loadFlags |= FT_LOAD_NO_HINTING;
668 /* set the base-line based on the string ascent */
669 if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox, utf8))
673 i_render_init(&render, im, bbox[BBOX_POS_WIDTH] - bbox[BBOX_NEG_WIDTH]);
676 /* this may need adjustment */
677 tx -= bbox[0] * handle->matrix[0] + bbox[5] * handle->matrix[1] + handle->matrix[2];
678 ty += bbox[0] * handle->matrix[3] + bbox[5] * handle->matrix[4] + handle->matrix[5];
683 c = i_utf8_advance(&text, &len);
685 i_push_error(0, "invalid UTF8 character");
690 c = (unsigned char)*text++;
694 index = FT_Get_Char_Index(handle->face, c);
695 error = FT_Load_Glyph(handle->face, index, loadFlags);
697 ft2_push_message(error);
698 i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)",
701 i_render_done(&render);
704 slot = handle->face->glyph;
708 error = FT_Render_Glyph(slot, aa ? ft_render_mode_normal : ft_render_mode_mono);
710 ft2_push_message(error);
711 i_push_errorf(0, "rendering glyph 0x%04X (character \\x%02X)");
713 i_render_done(&render);
716 if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) {
717 bmp = slot->bitmap.buffer;
718 for (y = 0; y < slot->bitmap.rows; ++y) {
721 for (x = 0; x < slot->bitmap.width; ++x) {
723 i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, cl);
731 bmp += slot->bitmap.pitch;
735 /* grey scale or something we can treat as greyscale */
736 /* we create a map to convert from the bitmap values to 0-255 */
737 if (last_mode != slot->bitmap.pixel_mode
738 || last_grays != slot->bitmap.num_grays) {
739 if (!make_bmp_map(&slot->bitmap, map))
741 last_mode = slot->bitmap.pixel_mode;
742 last_grays = slot->bitmap.num_grays;
745 bmp = slot->bitmap.buffer;
746 for (y = 0; y < slot->bitmap.rows; ++y) {
747 if (last_mode == ft_pixel_mode_grays &&
749 for (x = 0; x < slot->bitmap.width; ++x)
750 bmp[x] = map[bmp[x]];
752 i_render_color(&render, tx + slot->bitmap_left, ty-slot->bitmap_top+y,
753 slot->bitmap.width, bmp, cl);
754 bmp += slot->bitmap.pitch;
759 tx += slot->advance.x / 64;
760 ty -= slot->advance.y / 64;
764 i_render_done(&render);
770 =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)
772 Renders I<text> to (I<tx>, I<ty>) in I<im> to I<channel> at the given
773 I<cheight> and I<cwidth>.
775 If align is 0, then the text is rendered with the top-left of the
776 first character at (I<tx>, I<ty>). If align is non-zero then the text
777 is rendered with (I<tx>, I<ty>) aligned with the base-line of the
780 If aa is non-zero then the text is anti-aliased.
782 Returns non-zero on success.
788 i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, int channel,
789 double cheight, double cwidth, char const *text, int len, int align,
790 int aa, int vlayout, int utf8) {
796 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",
797 handle, im, tx, ty, channel, cheight, cwidth, text, len));
799 if (vlayout && !FT_HAS_VERTICAL(handle->face)) {
800 i_push_error(0, "face has no vertical metrics");
804 if (!i_ft2_bbox_r(handle, cheight, cwidth, text, len, vlayout, utf8, bbox))
807 work = i_img_empty_ch(NULL, bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, 1);
809 if (!i_ft2_text(handle, work, -bbox[0], -bbox[1], &cl, cheight, cwidth,
810 text, len, 1, aa, vlayout, utf8))
818 /* render to the specified channel */
819 /* this will be sped up ... */
820 for (y = 0; y < work->ysize; ++y) {
821 for (x = 0; x < work->xsize; ++x) {
822 i_gpix(work, x, y, &cl);
823 i_gpix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
824 cl2.channel[channel] = cl.channel[0];
825 i_ppix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
833 =item i_ft2_has_chars(handle, char *text, int len, int utf8, char *out)
835 Check if the given characters are defined by the font.
837 Returns the number of characters that were checked.
841 int i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, int len,
842 int utf8, char *out) {
844 mm_log((1, "i_ft2_has_chars(handle %p, text %p, len %d, utf8 %d)\n",
845 handle, text, len, utf8));
851 c = i_utf8_advance(&text, &len);
853 i_push_error(0, "invalid UTF8 character");
858 c = (unsigned char)*text++;
862 index = FT_Get_Char_Index(handle->face, c);
870 /* uses a method described in fterrors.h to build an error translation
873 #undef __FTERRORS_H__
874 #define FT_ERRORDEF(e, v, s) case v: i_push_error(code, s); return;
875 #define FT_ERROR_START_LIST
876 #define FT_ERROR_END_LIST
881 =head2 Internal Functions
883 These functions are used in the implementation of freetyp2.c and should not
884 (usually cannot) be called from outside it.
888 =item ft2_push_message(int code)
890 Pushes an error message corresponding to code onto the error stack.
894 static void ft2_push_message(int code) {
901 sprintf(unknown, "Unknown Freetype2 error code 0x%04X\n", code);
902 i_push_error(code, unknown);
906 =item make_bmp_map(FT_Bitmap *bitmap, unsigned char *map)
908 Creates a map to convert grey levels from the glyphs bitmap into
909 values scaled 0..255.
914 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map) {
918 switch (bitmap->pixel_mode) {
919 case ft_pixel_mode_grays:
920 scale = bitmap->num_grays;
924 i_push_errorf(0, "I can't handle pixel mode %d", bitmap->pixel_mode);
928 /* build the table */
929 for (i = 0; i < scale; ++i)
930 map[i] = i * 255 / (bitmap->num_grays - 1);
935 /* FREETYPE_PATCH was introduced in 2.0.6, we don't want a false
936 positive on 2.0.0 to 2.0.4, so we accept a false negative in 2.0.5 */
937 #ifndef FREETYPE_PATCH
938 #define FREETYPE_PATCH 4
941 /* FT_Get_Postscript_Name() was introduced in FT2.0.5 */
942 #define IM_HAS_FACE_NAME (FREETYPE_MINOR > 0 || FREETYPE_PATCH >= 5)
943 /* #define IM_HAS_FACE_NAME 0 */
946 =item i_ft2_face_name(handle, name_buf, name_buf_size)
948 Fills the given buffer with the Postscript Face name of the font,
955 i_ft2_face_name(FT2_Fonthandle *handle, char *name_buf, size_t name_buf_size) {
957 char const *name = FT_Get_Postscript_Name(handle->face);
962 strncpy(name_buf, name, name_buf_size);
963 name_buf[name_buf_size-1] = '\0';
965 return strlen(name) + 1;
968 i_push_error(0, "no face name available");
975 i_push_error(0, "Freetype 2.0.6 or later required");
983 i_ft2_can_face_name(void) {
984 return IM_HAS_FACE_NAME;
987 /* FT_Has_PS_Glyph_Names() was introduced in FT2.1.1 */
988 /* well, I assume FREETYPE_MAJOR is 2, since we're here */
989 #if FREETYPE_MINOR < 1 || (FREETYPE_MINOR == 1 && FREETYPE_PATCH < 1)
990 #define FT_Has_PS_Glyph_Names(face) (FT_HAS_GLYPH_NAMES(face))
994 i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned long ch, char *name_buf,
995 size_t name_buf_size, int reliable_only) {
996 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
999 i_push_error(0, "FT2 configured without glyph name support");
1007 if (!FT_HAS_GLYPH_NAMES(handle->face)) {
1008 i_push_error(0, "no glyph names in font");
1012 if (reliable_only && !FT_Has_PS_Glyph_Names(handle->face)) {
1013 i_push_error(0, "no reliable glyph names in font - set reliable_only to 0 to try anyway");
1018 index = FT_Get_Char_Index(handle->face, ch);
1021 FT_Error error = FT_Get_Glyph_Name(handle->face, index, name_buf,
1024 ft2_push_message(error);
1029 return strlen(name_buf) + 1;
1036 i_push_error(0, "no glyph for that character");
1044 i_ft2_can_do_glyph_names(void) {
1045 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1053 i_ft2_face_has_glyph_names(FT2_Fonthandle *handle) {
1054 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1057 return FT_Has_PS_Glyph_Names(handle->face);
1062 i_ft2_is_multiple_master(FT2_Fonthandle *handle) {
1065 return handle->has_mm;
1072 i_ft2_get_multiple_masters(FT2_Fonthandle *handle, i_font_mm *mm) {
1075 FT_Multi_Master *mms = &handle->mm;
1078 if (!handle->has_mm) {
1079 i_push_error(0, "Font has no multiple masters");
1082 mm->num_axis = mms->num_axis;
1083 mm->num_designs = mms->num_designs;
1084 for (i = 0; i < mms->num_axis; ++i) {
1085 mm->axis[i].name = mms->axis[i].name;
1086 mm->axis[i].minimum = mms->axis[i].minimum;
1087 mm->axis[i].maximum = mms->axis[i].maximum;
1093 i_push_error(0, "Multiple master functions unavailable");
1099 i_ft2_set_mm_coords(FT2_Fonthandle *handle, int coord_count, const long *coords) {
1102 FT_Long ftcoords[T1_MAX_MM_AXIS];
1106 if (!handle->has_mm) {
1107 i_push_error(0, "Font has no multiple masters");
1110 if (coord_count != handle->mm.num_axis) {
1111 i_push_error(0, "Number of MM coords doesn't match MM axis count");
1114 for (i = 0; i < coord_count; ++i)
1115 ftcoords[i] = coords[i];
1117 error = FT_Set_MM_Design_Coordinates(handle->face, coord_count, ftcoords);
1119 ft2_push_message(error);
1126 i_push_error(0, "Multiple master functions unavailable");
1137 Tony Cook <tony@develop-help.com>, with a fair amount of help from
1138 reading the code in font.c.
1142 font.c, Imager::Font(3), Imager(3)
1144 http://www.freetype.org/