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.
42 #include FT_FREETYPE_H
43 #ifdef FT_MULTIPLE_MASTERS_H
44 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
46 #include FT_MULTIPLE_MASTERS_H
50 static void ft2_push_message(int code);
52 static int ft2_initialized = 0;
53 static FT_Library library;
55 static int i_min(int a, int b);
56 static int i_max(int a, int b);
59 =item i_ft2_init(void)
61 Initializes the Freetype 2 library.
63 Returns true on success, false on failure.
72 error = FT_Init_FreeType(&library);
74 ft2_push_message(error);
75 i_push_error(0, "Initializing Freetype2");
84 struct FT2_Fonthandle {
90 /* used to adjust so we can align the draw point to the top-left */
94 /* Multiple master data if any */
100 /* the following is used to select a "best" encoding */
101 static struct enc_score {
102 FT_Encoding encoding;
106 /* the selections here are fairly arbitrary
107 ideally we need to give the user a list of encodings available
108 and a mechanism to choose one */
109 { ft_encoding_unicode, 10 },
110 { ft_encoding_sjis, 8 },
111 { ft_encoding_gb2312, 8 },
112 { ft_encoding_big5, 8 },
113 { ft_encoding_wansung, 8 },
114 { ft_encoding_johab, 8 },
115 { ft_encoding_latin_2, 6 },
116 { ft_encoding_apple_roman, 6 },
117 { ft_encoding_adobe_standard, 6 },
118 { ft_encoding_adobe_expert, 6 },
122 =item i_ft2_new(char *name, int index)
124 Creates a new font object, from the file given by I<name>. I<index>
125 is the index of the font in a file with multiple fonts, where 0 is the
128 Return NULL on failure.
134 i_ft2_new(const char *name, int index) {
136 FT2_Fonthandle *result;
139 FT_Encoding encoding;
142 mm_log((1, "i_ft2_new(name %p, index %d)\n", name, index));
144 if (!ft2_initialized && !i_ft2_init())
148 error = FT_New_Face(library, name, index, &face);
150 ft2_push_message(error);
151 i_push_error(error, "Opening face");
152 mm_log((2, "error opening face '%s': %d\n", name, error));
156 encoding = face->num_charmaps ? face->charmaps[0]->encoding : ft_encoding_unicode;
158 for (i = 0; i < face->num_charmaps; ++i) {
159 FT_Encoding enc_entry = face->charmaps[i]->encoding;
160 mm_log((2, "i_ft2_new, encoding %lX platform %u encoding %u\n",
161 enc_entry, face->charmaps[i]->platform_id,
162 face->charmaps[i]->encoding_id));
163 for (j = 0; j < sizeof(enc_scores) / sizeof(*enc_scores); ++j) {
164 if (enc_scores[j].encoding == enc_entry && enc_scores[j].score > score) {
165 encoding = enc_entry;
166 score = enc_scores[j].score;
171 FT_Select_Charmap(face, encoding);
172 mm_log((2, "i_ft2_new, selected encoding %lX\n", encoding));
174 result = mymalloc(sizeof(FT2_Fonthandle));
176 result->xdpi = result->ydpi = 72;
177 result->encoding = encoding;
179 /* by default we disable hinting on a call to i_ft2_settransform()
180 if we don't do this, then the hinting can the untransformed text
181 to be a different size to the transformed text.
182 Obviously we have it initially enabled.
186 /* I originally forgot this: :/ */
187 /*i_ft2_settransform(result, matrix); */
188 result->matrix[0] = 1; result->matrix[1] = 0; result->matrix[2] = 0;
189 result->matrix[3] = 0; result->matrix[4] = 1; result->matrix[5] = 0;
193 FT_Multi_Master *mm = &result->mm;
196 if ((face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) != 0
197 && (error = FT_Get_Multi_Master(face, mm)) == 0) {
198 mm_log((2, "MM Font, %d axes, %d designs\n", mm->num_axis, mm->num_designs));
199 for (i = 0; i < mm->num_axis; ++i) {
200 mm_log((2, " axis %d name %s range %ld - %ld\n", i, mm->axis[i].name,
201 (long)(mm->axis[i].minimum), (long)(mm->axis[i].maximum)));
206 mm_log((2, "No multiple masters\n"));
216 =item i_ft2_destroy(FT2_Fonthandle *handle)
218 Destroys a font object, which must have been the return value of
224 i_ft2_destroy(FT2_Fonthandle *handle) {
225 FT_Done_Face(handle->face);
230 =item i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi)
232 Sets the resolution in dots per inch at which point sizes scaled, by
233 default xdpi and ydpi are 72, so that 1 point maps to 1 pixel.
235 Both xdpi and ydpi should be positive.
237 Return true on success.
242 i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi) {
244 if (xdpi > 0 && ydpi > 0) {
250 i_push_error(0, "resolutions must be positive");
256 =item i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi)
258 Retrieves the current horizontal and vertical resolutions at which
259 point sizes are scaled.
264 i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi) {
265 *xdpi = handle->xdpi;
266 *ydpi = handle->ydpi;
272 =item i_ft2_settransform(FT2_FontHandle *handle, double *matrix)
274 Sets a transormation matrix for output.
276 This should be a 2 x 3 matrix like:
278 matrix[0] matrix[1] matrix[2]
279 matrix[3] matrix[4] matrix[5]
284 i_ft2_settransform(FT2_Fonthandle *handle, const double *matrix) {
289 m.xx = matrix[0] * 65536;
290 m.xy = matrix[1] * 65536;
291 v.x = matrix[2]; /* this could be pels of 26.6 fixed - not sure */
292 m.yx = matrix[3] * 65536;
293 m.yy = matrix[4] * 65536;
294 v.y = matrix[5]; /* see just above */
296 FT_Set_Transform(handle->face, &m, &v);
298 for (i = 0; i < 6; ++i)
299 handle->matrix[i] = matrix[i];
306 =item i_ft2_sethinting(FT2_Fonthandle *handle, int hinting)
308 If hinting is non-zero then glyph hinting is enabled, otherwise disabled.
310 i_ft2_settransform() disables hinting to prevent distortions in
311 gradual text transformations.
315 int i_ft2_sethinting(FT2_Fonthandle *handle, int hinting) {
316 handle->hint = hinting;
321 =item i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, size_t len, int *bbox)
323 Retrieves bounding box information for the font at the given
324 character width and height. This ignores the transformation matrix.
326 Returns non-zero on success.
331 i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth,
332 char const *text, size_t len, int *bbox, int utf8) {
337 int ascent = 0, descent = 0;
338 int glyph_ascent, glyph_descent;
339 FT_Glyph_Metrics *gm;
341 int loadFlags = FT_LOAD_DEFAULT;
344 mm_log((1, "i_ft2_bbox(handle %p, cheight %f, cwidth %f, text %p, len %d, bbox %p)\n",
345 handle, cheight, cwidth, text, len, bbox));
347 error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64,
348 handle->xdpi, handle->ydpi);
350 ft2_push_message(error);
351 i_push_error(0, "setting size");
355 loadFlags |= FT_LOAD_NO_HINTING;
362 c = i_utf8_advance(&text, &len);
364 i_push_error(0, "invalid UTF8 character");
369 c = (unsigned char)*text++;
373 index = FT_Get_Char_Index(handle->face, c);
374 error = FT_Load_Glyph(handle->face, index, loadFlags);
376 ft2_push_message(error);
377 i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)",
381 gm = &handle->face->glyph->metrics;
382 glyph_ascent = gm->horiBearingY / 64;
383 glyph_descent = glyph_ascent - gm->height/64;
385 start = gm->horiBearingX / 64;
386 /* handles -ve values properly */
387 ascent = glyph_ascent;
388 descent = glyph_descent;
392 if (glyph_ascent > ascent)
393 ascent = glyph_ascent;
394 if (glyph_descent < descent)
395 descent = glyph_descent;
397 width += gm->horiAdvance / 64;
401 handle the case where the right the of the character overlaps the
403 rightb = (gm->horiAdvance - gm->horiBearingX - gm->width)/64;
409 bbox[BBOX_NEG_WIDTH] = start;
410 bbox[BBOX_GLOBAL_DESCENT] = handle->face->size->metrics.descender / 64;
411 bbox[BBOX_POS_WIDTH] = width;
413 bbox[BBOX_POS_WIDTH] -= rightb;
414 bbox[BBOX_GLOBAL_ASCENT] = handle->face->size->metrics.ascender / 64;
415 bbox[BBOX_DESCENT] = descent;
416 bbox[BBOX_ASCENT] = ascent;
417 bbox[BBOX_ADVANCE_WIDTH] = width;
418 bbox[BBOX_RIGHT_BEARING] = rightb;
419 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]));
421 return BBOX_RIGHT_BEARING + 1;
425 =item transform_box(FT2_FontHandle *handle, int bbox[4])
427 bbox contains coorinates of a the top-left and bottom-right of a bounding
428 box relative to a point.
430 This is then transformed and the values in bbox[4] are the top-left
431 and bottom-right of the new bounding box.
433 This is meant to provide the bounding box of a transformed character
434 box. The problem is that if the character was round and is rotated,
435 the real bounding box isn't going to be much different from the
436 original, but this function will return a _bigger_ bounding box. I
437 suppose I could work my way through the glyph outline, but that's
442 void ft2_transform_box(FT2_Fonthandle *handle, int bbox[4]) {
444 double *matrix = handle->matrix;
446 work[0] = matrix[0] * bbox[0] + matrix[1] * bbox[1];
447 work[1] = matrix[3] * bbox[0] + matrix[4] * bbox[1];
448 work[2] = matrix[0] * bbox[2] + matrix[1] * bbox[1];
449 work[3] = matrix[3] * bbox[2] + matrix[4] * bbox[1];
450 work[4] = matrix[0] * bbox[0] + matrix[1] * bbox[3];
451 work[5] = matrix[3] * bbox[0] + matrix[4] * bbox[3];
452 work[6] = matrix[0] * bbox[2] + matrix[1] * bbox[3];
453 work[7] = matrix[3] * bbox[2] + matrix[4] * bbox[3];
455 bbox[0] = floor(i_min(i_min(work[0], work[2]),i_min(work[4], work[6])));
456 bbox[1] = floor(i_min(i_min(work[1], work[3]),i_min(work[5], work[7])));
457 bbox[2] = ceil(i_max(i_max(work[0], work[2]),i_max(work[4], work[6])));
458 bbox[3] = ceil(i_max(i_max(work[1], work[3]),i_max(work[5], work[7])));
462 =item expand_bounds(int bbox[4], int bbox2[4])
464 Treating bbox[] and bbox2[] as 2 bounding boxes, produces a new
465 bounding box in bbox[] that encloses both.
469 static void expand_bounds(int bbox[4], int bbox2[4]) {
470 bbox[0] = i_min(bbox[0], bbox2[0]);
471 bbox[1] = i_min(bbox[1], bbox2[1]);
472 bbox[2] = i_max(bbox[2], bbox2[2]);
473 bbox[3] = i_max(bbox[3], bbox2[3]);
477 =item i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, size_t len, int vlayout, int utf8, int *bbox)
479 Retrieves bounding box information for the font at the given
480 character width and height.
482 This version finds the rectangular bounding box of the glyphs, with
483 the text as transformed by the transformation matrix. As with
484 i_ft2_bbox (bbox[0], bbox[1]) will the the offset from the start of
485 the topline to the top-left of the bounding box. Unlike i_ft2_bbox()
486 this could be near the bottom left corner of the box.
488 (bbox[4], bbox[5]) is the offset to the start of the baseline.
489 (bbox[6], bbox[7]) is the offset from the start of the baseline to the
492 Returns non-zero on success.
497 i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth,
498 char const *text, size_t len, int vlayout, int utf8, int *bbox) {
503 int ascent = 0, descent = 0;
504 int glyph_ascent, glyph_descent;
505 FT_Glyph_Metrics *gm;
511 int loadFlags = FT_LOAD_DEFAULT;
514 loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
516 loadFlags |= FT_LOAD_NO_HINTING;
518 error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64,
519 handle->xdpi, handle->ydpi);
521 ft2_push_message(error);
522 i_push_error(0, "setting size");
530 c = i_utf8_advance(&text, &len);
532 i_push_error(0, "invalid UTF8 character");
537 c = (unsigned char)*text++;
541 index = FT_Get_Char_Index(handle->face, c);
542 error = FT_Load_Glyph(handle->face, index, loadFlags);
544 ft2_push_message(error);
545 i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)",
549 slot = handle->face->glyph;
552 /* these probably don't mean much for vertical layouts */
553 glyph_ascent = gm->horiBearingY / 64;
554 glyph_descent = glyph_ascent - gm->height/64;
556 work[0] = gm->vertBearingX;
557 work[1] = gm->vertBearingY;
560 work[0] = gm->horiBearingX;
561 work[1] = gm->horiBearingY;
563 work[2] = gm->width + work[0];
564 work[3] = work[1] - gm->height;
566 bbox[4] = work[0] * handle->matrix[0] + work[1] * handle->matrix[1] + handle->matrix[2];
567 bbox[5] = work[0] * handle->matrix[3] + work[1] * handle->matrix[4] + handle->matrix[5];
568 bbox[4] = bbox[4] < 0 ? -(-bbox[4] + 32)/64 : (bbox[4] + 32) / 64;
571 ft2_transform_box(handle, work);
572 for (i = 0; i < 4; ++i)
579 for (i = 0; i < 4; ++i)
581 ascent = glyph_ascent;
582 descent = glyph_descent;
586 expand_bounds(bounds, work);
588 x += slot->advance.x / 64;
589 y += slot->advance.y / 64;
591 if (glyph_ascent > ascent)
592 ascent = glyph_ascent;
593 if (glyph_descent > descent)
594 descent = glyph_descent;
598 handle the case where the right the of the character overlaps the
600 /*int rightb = gm->horiAdvance - gm->horiBearingX - gm->width;
602 width -= rightb / 64;*/
606 /* at this point bounds contains the bounds relative to the CP,
607 and x, y hold the final position relative to the CP */
614 bbox[1] = -bounds[3];
616 bbox[3] = -bounds[1];
624 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map);
627 =item i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl, double cheight, double cwidth, char *text, size_t len, int align, int aa)
629 Renders I<text> to (I<tx>, I<ty>) in I<im> using color I<cl> at the given
630 I<cheight> and I<cwidth>.
632 If align is 0, then the text is rendered with the top-left of the
633 first character at (I<tx>, I<ty>). If align is non-zero then the text
634 is rendered with (I<tx>, I<ty>) aligned with the base-line of the
637 If aa is non-zero then the text is anti-aliased.
639 Returns non-zero on success.
644 i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, const i_color *cl,
645 double cheight, double cwidth, char const *text, size_t len,
646 int align, int aa, int vlayout, int utf8) {
649 FT_Glyph_Metrics *gm;
650 int bbox[BOUNDING_BOX_COUNT];
654 unsigned char map[256];
655 char last_mode = ft_pixel_mode_none;
657 int loadFlags = FT_LOAD_DEFAULT;
660 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",
661 handle, im, tx, ty, cl, cheight, cwidth, text, align, aa));
664 if (!FT_HAS_VERTICAL(handle->face)) {
665 i_push_error(0, "face has no vertical metrics");
668 loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
671 loadFlags |= FT_LOAD_NO_HINTING;
673 /* set the base-line based on the string ascent */
674 if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox, utf8))
678 render = i_render_new(im, bbox[BBOX_POS_WIDTH] - bbox[BBOX_NEG_WIDTH]);
681 /* this may need adjustment */
682 tx -= bbox[0] * handle->matrix[0] + bbox[5] * handle->matrix[1] + handle->matrix[2];
683 ty += bbox[0] * handle->matrix[3] + bbox[5] * handle->matrix[4] + handle->matrix[5];
688 c = i_utf8_advance(&text, &len);
690 i_push_error(0, "invalid UTF8 character");
695 c = (unsigned char)*text++;
699 index = FT_Get_Char_Index(handle->face, c);
700 error = FT_Load_Glyph(handle->face, index, loadFlags);
702 ft2_push_message(error);
703 i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)",
706 i_render_delete(render);
709 slot = handle->face->glyph;
713 error = FT_Render_Glyph(slot, aa ? ft_render_mode_normal : ft_render_mode_mono);
715 ft2_push_message(error);
716 i_push_errorf(0, "rendering glyph 0x%04X (character \\x%02X)");
718 i_render_delete(render);
721 if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) {
722 bmp = slot->bitmap.buffer;
723 for (y = 0; y < slot->bitmap.rows; ++y) {
726 for (x = 0; x < slot->bitmap.width; ++x) {
728 i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, cl);
736 bmp += slot->bitmap.pitch;
740 /* grey scale or something we can treat as greyscale */
741 /* we create a map to convert from the bitmap values to 0-255 */
742 if (last_mode != slot->bitmap.pixel_mode
743 || last_grays != slot->bitmap.num_grays) {
744 if (!make_bmp_map(&slot->bitmap, map))
746 last_mode = slot->bitmap.pixel_mode;
747 last_grays = slot->bitmap.num_grays;
750 bmp = slot->bitmap.buffer;
751 for (y = 0; y < slot->bitmap.rows; ++y) {
752 if (last_mode == ft_pixel_mode_grays &&
754 for (x = 0; x < slot->bitmap.width; ++x)
755 bmp[x] = map[bmp[x]];
757 i_render_color(render, tx + slot->bitmap_left, ty-slot->bitmap_top+y,
758 slot->bitmap.width, bmp, cl);
759 bmp += slot->bitmap.pitch;
764 tx += slot->advance.x / 64;
765 ty -= slot->advance.y / 64;
769 i_render_delete(render);
775 =item i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, int channel, double cheight, double cwidth, char *text, size_t len, int align, int aa)
777 Renders I<text> to (I<tx>, I<ty>) in I<im> to I<channel> at the given
778 I<cheight> and I<cwidth>.
780 If align is 0, then the text is rendered with the top-left of the
781 first character at (I<tx>, I<ty>). If align is non-zero then the text
782 is rendered with (I<tx>, I<ty>) aligned with the base-line of the
785 If aa is non-zero then the text is anti-aliased.
787 Returns non-zero on success.
793 i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, int channel,
794 double cheight, double cwidth, char const *text, size_t len, int align,
795 int aa, int vlayout, int utf8) {
801 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",
802 handle, im, tx, ty, channel, cheight, cwidth, text, len));
804 if (vlayout && !FT_HAS_VERTICAL(handle->face)) {
805 i_push_error(0, "face has no vertical metrics");
809 if (!i_ft2_bbox_r(handle, cheight, cwidth, text, len, vlayout, utf8, bbox))
812 work = i_img_8_new(bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, 1);
814 if (!i_ft2_text(handle, work, -bbox[0], -bbox[1], &cl, cheight, cwidth,
815 text, len, 1, aa, vlayout, utf8))
823 /* render to the specified channel */
824 /* this will be sped up ... */
825 for (y = 0; y < work->ysize; ++y) {
826 for (x = 0; x < work->xsize; ++x) {
827 i_gpix(work, x, y, &cl);
828 i_gpix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
829 cl2.channel[channel] = cl.channel[0];
830 i_ppix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
838 =item i_ft2_has_chars(handle, char *text, size_t len, int utf8, char *out)
840 Check if the given characters are defined by the font.
842 Returns the number of characters that were checked.
846 int i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, size_t len,
847 int utf8, char *out) {
849 mm_log((1, "i_ft2_has_chars(handle %p, text %p, len %d, utf8 %d)\n",
850 handle, text, len, utf8));
856 c = i_utf8_advance(&text, &len);
858 i_push_error(0, "invalid UTF8 character");
863 c = (unsigned char)*text++;
867 index = FT_Get_Char_Index(handle->face, c);
875 /* uses a method described in fterrors.h to build an error translation
878 #undef __FTERRORS_H__
879 #define FT_ERRORDEF(e, v, s) case v: i_push_error(code, s); return;
880 #define FT_ERROR_START_LIST
881 #define FT_ERROR_END_LIST
886 =head2 Internal Functions
888 These functions are used in the implementation of freetyp2.c and should not
889 (usually cannot) be called from outside it.
893 =item ft2_push_message(int code)
895 Pushes an error message corresponding to code onto the error stack.
899 static void ft2_push_message(int code) {
906 sprintf(unknown, "Unknown Freetype2 error code 0x%04X\n", code);
907 i_push_error(code, unknown);
911 =item make_bmp_map(FT_Bitmap *bitmap, unsigned char *map)
913 Creates a map to convert grey levels from the glyphs bitmap into
914 values scaled 0..255.
919 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map) {
923 switch (bitmap->pixel_mode) {
924 case ft_pixel_mode_grays:
925 scale = bitmap->num_grays;
929 i_push_errorf(0, "I can't handle pixel mode %d", bitmap->pixel_mode);
933 /* build the table */
934 for (i = 0; i < scale; ++i)
935 map[i] = i * 255 / (bitmap->num_grays - 1);
940 /* FREETYPE_PATCH was introduced in 2.0.6, we don't want a false
941 positive on 2.0.0 to 2.0.4, so we accept a false negative in 2.0.5 */
942 #ifndef FREETYPE_PATCH
943 #define FREETYPE_PATCH 4
946 /* FT_Get_Postscript_Name() was introduced in FT2.0.5 */
947 #define IM_HAS_FACE_NAME (FREETYPE_MINOR > 0 || FREETYPE_PATCH >= 5)
948 /* #define IM_HAS_FACE_NAME 0 */
951 =item i_ft2_face_name(handle, name_buf, name_buf_size)
953 Fills the given buffer with the Postscript Face name of the font,
960 i_ft2_face_name(FT2_Fonthandle *handle, char *name_buf, size_t name_buf_size) {
962 char const *name = FT_Get_Postscript_Name(handle->face);
967 strncpy(name_buf, name, name_buf_size);
968 name_buf[name_buf_size-1] = '\0';
970 return strlen(name) + 1;
973 i_push_error(0, "no face name available");
980 i_push_error(0, "Freetype 2.0.6 or later required");
988 i_ft2_can_face_name(void) {
989 return IM_HAS_FACE_NAME;
992 /* FT_Has_PS_Glyph_Names() was introduced in FT2.1.1 */
993 /* well, I assume FREETYPE_MAJOR is 2, since we're here */
994 #if FREETYPE_MINOR < 1 || (FREETYPE_MINOR == 1 && FREETYPE_PATCH < 1)
995 #define FT_Has_PS_Glyph_Names(face) (FT_HAS_GLYPH_NAMES(face))
999 i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned long ch, char *name_buf,
1000 size_t name_buf_size, int reliable_only) {
1001 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1004 i_push_error(0, "FT2 configured without glyph name support");
1012 if (!FT_HAS_GLYPH_NAMES(handle->face)) {
1013 i_push_error(0, "no glyph names in font");
1017 if (reliable_only && !FT_Has_PS_Glyph_Names(handle->face)) {
1018 i_push_error(0, "no reliable glyph names in font - set reliable_only to 0 to try anyway");
1023 index = FT_Get_Char_Index(handle->face, ch);
1026 FT_Error error = FT_Get_Glyph_Name(handle->face, index, name_buf,
1029 ft2_push_message(error);
1034 return strlen(name_buf) + 1;
1041 i_push_error(0, "no glyph for that character");
1049 i_ft2_can_do_glyph_names(void) {
1050 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1058 i_ft2_face_has_glyph_names(FT2_Fonthandle *handle) {
1059 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1062 return FT_Has_PS_Glyph_Names(handle->face);
1067 i_ft2_is_multiple_master(FT2_Fonthandle *handle) {
1070 return handle->has_mm;
1077 i_ft2_get_multiple_masters(FT2_Fonthandle *handle, i_font_mm *mm) {
1080 FT_Multi_Master *mms = &handle->mm;
1083 if (!handle->has_mm) {
1084 i_push_error(0, "Font has no multiple masters");
1087 mm->num_axis = mms->num_axis;
1088 mm->num_designs = mms->num_designs;
1089 for (i = 0; i < mms->num_axis; ++i) {
1090 mm->axis[i].name = mms->axis[i].name;
1091 mm->axis[i].minimum = mms->axis[i].minimum;
1092 mm->axis[i].maximum = mms->axis[i].maximum;
1098 i_push_error(0, "Multiple master functions unavailable");
1104 i_ft2_set_mm_coords(FT2_Fonthandle *handle, int coord_count, const long *coords) {
1107 FT_Long ftcoords[T1_MAX_MM_AXIS];
1111 if (!handle->has_mm) {
1112 i_push_error(0, "Font has no multiple masters");
1115 if (coord_count != handle->mm.num_axis) {
1116 i_push_error(0, "Number of MM coords doesn't match MM axis count");
1119 for (i = 0; i < coord_count; ++i)
1120 ftcoords[i] = coords[i];
1122 error = FT_Set_MM_Design_Coordinates(handle->face, coord_count, ftcoords);
1124 ft2_push_message(error);
1131 i_push_error(0, "Multiple master functions unavailable");
1138 i_min(int a, int b) {
1139 return a < b ? a : b;
1143 i_max(int a, int b) {
1144 return a > b ? a : b;
1152 Tony Cook <tony@develop-help.com>, with a fair amount of help from
1153 reading the code in font.c.
1157 font.c, Imager::Font(3), Imager(3)
1159 http://www.freetype.org/