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;
649 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",
650 handle, im, tx, ty, cl, cheight, cwidth, text, align, aa));
653 if (!FT_HAS_VERTICAL(handle->face)) {
654 i_push_error(0, "face has no vertical metrics");
657 loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
660 loadFlags |= FT_LOAD_NO_HINTING;
662 /* set the base-line based on the string ascent */
663 if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox, utf8))
667 /* this may need adjustment */
668 tx -= bbox[0] * handle->matrix[0] + bbox[5] * handle->matrix[1] + handle->matrix[2];
669 ty += bbox[0] * handle->matrix[3] + bbox[5] * handle->matrix[4] + handle->matrix[5];
674 c = i_utf8_advance(&text, &len);
676 i_push_error(0, "invalid UTF8 character");
681 c = (unsigned char)*text++;
685 index = FT_Get_Char_Index(handle->face, c);
686 error = FT_Load_Glyph(handle->face, index, loadFlags);
688 ft2_push_message(error);
689 i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)",
693 slot = handle->face->glyph;
697 error = FT_Render_Glyph(slot, aa ? ft_render_mode_normal : ft_render_mode_mono);
699 ft2_push_message(error);
700 i_push_errorf(0, "rendering glyph 0x%04X (character \\x%02X)");
703 if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) {
704 bmp = slot->bitmap.buffer;
705 for (y = 0; y < slot->bitmap.rows; ++y) {
708 for (x = 0; x < slot->bitmap.width; ++x) {
710 i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, cl);
718 bmp += slot->bitmap.pitch;
722 /* grey scale or something we can treat as greyscale */
723 /* we create a map to convert from the bitmap values to 0-255 */
724 if (last_mode != slot->bitmap.pixel_mode
725 || last_grays != slot->bitmap.num_grays) {
726 if (!make_bmp_map(&slot->bitmap, map))
728 last_mode = slot->bitmap.pixel_mode;
729 last_grays = slot->bitmap.num_grays;
732 bmp = slot->bitmap.buffer;
733 for (y = 0; y < slot->bitmap.rows; ++y) {
734 for (x = 0; x < slot->bitmap.width; ++x) {
735 int value = map[bmp[x]];
737 i_gpix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, &pel);
738 for (ch = 0; ch < im->channels; ++ch) {
740 ((255-value)*pel.channel[ch] + value * cl->channel[ch]) / 255;
742 i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, &pel);
745 bmp += slot->bitmap.pitch;
750 tx += slot->advance.x / 64;
751 ty -= slot->advance.y / 64;
758 =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)
760 Renders I<text> to (I<tx>, I<ty>) in I<im> to I<channel> at the given
761 I<cheight> and I<cwidth>.
763 If align is 0, then the text is rendered with the top-left of the
764 first character at (I<tx>, I<ty>). If align is non-zero then the text
765 is rendered with (I<tx>, I<ty>) aligned with the base-line of the
768 If aa is non-zero then the text is anti-aliased.
770 Returns non-zero on success.
776 i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, int channel,
777 double cheight, double cwidth, char const *text, int len, int align,
778 int aa, int vlayout, int utf8) {
784 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",
785 handle, im, tx, ty, channel, cheight, cwidth, text, len));
787 if (vlayout && !FT_HAS_VERTICAL(handle->face)) {
788 i_push_error(0, "face has no vertical metrics");
792 if (!i_ft2_bbox_r(handle, cheight, cwidth, text, len, vlayout, utf8, bbox))
795 work = i_img_empty_ch(NULL, bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, 1);
797 if (!i_ft2_text(handle, work, -bbox[0], -bbox[1], &cl, cheight, cwidth,
798 text, len, 1, aa, vlayout, utf8))
806 /* render to the specified channel */
807 /* this will be sped up ... */
808 for (y = 0; y < work->ysize; ++y) {
809 for (x = 0; x < work->xsize; ++x) {
810 i_gpix(work, x, y, &cl);
811 i_gpix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
812 cl2.channel[channel] = cl.channel[0];
813 i_ppix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
821 =item i_ft2_has_chars(handle, char *text, int len, int utf8, char *out)
823 Check if the given characters are defined by the font.
825 Returns the number of characters that were checked.
829 int i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, int len,
830 int utf8, char *out) {
832 mm_log((1, "i_ft2_has_chars(handle %p, text %p, len %d, utf8 %d)\n",
833 handle, text, len, utf8));
839 c = i_utf8_advance(&text, &len);
841 i_push_error(0, "invalid UTF8 character");
846 c = (unsigned char)*text++;
850 index = FT_Get_Char_Index(handle->face, c);
858 /* uses a method described in fterrors.h to build an error translation
861 #undef __FTERRORS_H__
862 #define FT_ERRORDEF(e, v, s) case v: i_push_error(code, s); return;
863 #define FT_ERROR_START_LIST
864 #define FT_ERROR_END_LIST
869 =head2 Internal Functions
871 These functions are used in the implementation of freetyp2.c and should not
872 (usually cannot) be called from outside it.
876 =item ft2_push_message(int code)
878 Pushes an error message corresponding to code onto the error stack.
882 static void ft2_push_message(int code) {
889 sprintf(unknown, "Unknown Freetype2 error code 0x%04X\n", code);
890 i_push_error(code, unknown);
894 =item make_bmp_map(FT_Bitmap *bitmap, unsigned char *map)
896 Creates a map to convert grey levels from the glyphs bitmap into
897 values scaled 0..255.
902 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map) {
906 switch (bitmap->pixel_mode) {
907 case ft_pixel_mode_grays:
908 scale = bitmap->num_grays;
912 i_push_errorf(0, "I can't handle pixel mode %d", bitmap->pixel_mode);
916 /* build the table */
917 for (i = 0; i < scale; ++i)
918 map[i] = i * 255 / (bitmap->num_grays - 1);
923 /* FREETYPE_PATCH was introduced in 2.0.6, we don't want a false
924 positive on 2.0.0 to 2.0.4, so we accept a false negative in 2.0.5 */
925 #ifndef FREETYPE_PATCH
926 #define FREETYPE_PATCH 4
929 /* FT_Get_Postscript_Name() was introduced in FT2.0.5 */
930 #define IM_HAS_FACE_NAME (FREETYPE_MINOR > 0 || FREETYPE_PATCH >= 5)
931 /* #define IM_HAS_FACE_NAME 0 */
934 =item i_ft2_face_name(handle, name_buf, name_buf_size)
936 Fills the given buffer with the Postscript Face name of the font,
943 i_ft2_face_name(FT2_Fonthandle *handle, char *name_buf, size_t name_buf_size) {
945 char const *name = FT_Get_Postscript_Name(handle->face);
950 strncpy(name_buf, name, name_buf_size);
951 name_buf[name_buf_size-1] = '\0';
953 return strlen(name) + 1;
956 i_push_error(0, "no face name available");
963 i_push_error(0, "Freetype 2.0.6 or later required");
971 i_ft2_can_face_name(void) {
972 return IM_HAS_FACE_NAME;
975 /* FT_Has_PS_Glyph_Names() was introduced in FT2.1.1 */
976 /* well, I assume FREETYPE_MAJOR is 2, since we're here */
977 #if FREETYPE_MINOR < 1 || (FREETYPE_MINOR == 1 && FREETYPE_PATCH < 1)
978 #define FT_Has_PS_Glyph_Names(face) (FT_HAS_GLYPH_NAMES(face))
982 i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned long ch, char *name_buf,
983 size_t name_buf_size, int reliable_only) {
984 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
987 i_push_error(0, "FT2 configured without glyph name support");
995 if (!FT_HAS_GLYPH_NAMES(handle->face)) {
996 i_push_error(0, "no glyph names in font");
1000 if (reliable_only && !FT_Has_PS_Glyph_Names(handle->face)) {
1001 i_push_error(0, "no reliable glyph names in font - set reliable_only to 0 to try anyway");
1006 index = FT_Get_Char_Index(handle->face, ch);
1009 FT_Error error = FT_Get_Glyph_Name(handle->face, index, name_buf,
1012 ft2_push_message(error);
1017 return strlen(name_buf) + 1;
1024 i_push_error(0, "no glyph for that character");
1032 i_ft2_can_do_glyph_names(void) {
1033 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1041 i_ft2_face_has_glyph_names(FT2_Fonthandle *handle) {
1042 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1045 return FT_Has_PS_Glyph_Names(handle->face);
1050 i_ft2_is_multiple_master(FT2_Fonthandle *handle) {
1053 return handle->has_mm;
1060 i_ft2_get_multiple_masters(FT2_Fonthandle *handle, i_font_mm *mm) {
1063 FT_Multi_Master *mms = &handle->mm;
1066 if (!handle->has_mm) {
1067 i_push_error(0, "Font has no multiple masters");
1070 mm->num_axis = mms->num_axis;
1071 mm->num_designs = mms->num_designs;
1072 for (i = 0; i < mms->num_axis; ++i) {
1073 mm->axis[i].name = mms->axis[i].name;
1074 mm->axis[i].minimum = mms->axis[i].minimum;
1075 mm->axis[i].maximum = mms->axis[i].maximum;
1081 i_push_error(0, "Multiple master functions unavailable");
1087 i_ft2_set_mm_coords(FT2_Fonthandle *handle, int coord_count, const long *coords) {
1090 FT_Long ftcoords[T1_MAX_MM_AXIS];
1094 if (!handle->has_mm) {
1095 i_push_error(0, "Font has no multiple masters");
1098 if (coord_count != handle->mm.num_axis) {
1099 i_push_error(0, "Number of MM coords doesn't match MM axis count");
1102 for (i = 0; i < coord_count; ++i)
1103 ftcoords[i] = coords[i];
1105 error = FT_Set_MM_Design_Coordinates(handle->face, coord_count, ftcoords);
1107 ft2_push_message(error);
1114 i_push_error(0, "Multiple master functions unavailable");
1125 Tony Cook <tony@develop-help.com>, with a fair amount of help from
1126 reading the code in font.c.
1130 font.c, Imager::Font(3), Imager(3)
1132 http://www.freetype.org/