X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/3dec2c92bebd1d444fec581f181350ca046d6de7..66dd08539796edaa9e6a900b5d36f07920ce90cc:/freetyp2.c diff --git a/freetyp2.c b/freetyp2.c index 89508e2e..4d30c5c0 100644 --- a/freetyp2.c +++ b/freetyp2.c @@ -12,8 +12,8 @@ freetyp2.c - font support via the FreeType library version 2. if (!i_ft2_getdpi(font, &xdpi, &ydpi)) { error } double matrix[6]; if (!i_ft2_settransform(font, matrix)) { error } - int bbox[6]; - if (!i_ft2_bbox(font, cheight, cwidth, text, length, bbox)) { error } + int bbox[BOUNDING_BOX_COUNT]; + if (!i_ft2_bbox(font, cheight, cwidth, text, length, bbox, utf8)) { error } i_img *im = ...; i_color cl; if (!i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, length, align, @@ -34,13 +34,18 @@ Truetype, Type1 and Windows FNT. =cut */ -#include "image.h" +#include "imager.h" #include #include #include FT_FREETYPE_H +#ifdef FT_MULTIPLE_MASTERS_H +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT +#define IM_FT2_MM +#include FT_MULTIPLE_MASTERS_H +#endif +#endif static void ft2_push_message(int code); -static unsigned long utf8_advance(char **p, int *len); static FT_Library library; @@ -71,9 +76,37 @@ struct FT2_Fonthandle { FT_Face face; int xdpi, ydpi; int hint; + FT_Encoding encoding; /* used to adjust so we can align the draw point to the top-left */ double matrix[6]; + +#ifdef IM_FT2_MM + /* Multiple master data if any */ + int has_mm; + FT_Multi_Master mm; +#endif +}; + +/* the following is used to select a "best" encoding */ +static struct enc_score { + FT_Encoding encoding; + int score; +} enc_scores[] = +{ + /* the selections here are fairly arbitrary + ideally we need to give the user a list of encodings available + and a mechanism to choose one */ + { ft_encoding_unicode, 10 }, + { ft_encoding_sjis, 8 }, + { ft_encoding_gb2312, 8 }, + { ft_encoding_big5, 8 }, + { ft_encoding_wansung, 8 }, + { ft_encoding_johab, 8 }, + { ft_encoding_latin_2, 6 }, + { ft_encoding_apple_roman, 6 }, + { ft_encoding_adobe_standard, 6 }, + { ft_encoding_adobe_expert, 6 }, }; /* @@ -89,12 +122,13 @@ Return NULL on failure. */ FT2_Fonthandle * -i_ft2_new(char *name, int index) { +i_ft2_new(const char *name, int index) { FT_Error error; FT2_Fonthandle *result; FT_Face face; - double matrix[6] = { 1, 0, 0, - 0, 1, 0 }; + int i, j; + FT_Encoding encoding; + int score; mm_log((1, "i_ft2_new(name %p, index %d)\n", name, index)); @@ -103,12 +137,32 @@ i_ft2_new(char *name, int index) { if (error) { ft2_push_message(error); i_push_error(error, "Opening face"); + mm_log((2, "error opening face '%s': %d\n", name, error)); return NULL; } + encoding = face->num_charmaps ? face->charmaps[0]->encoding : ft_encoding_unicode; + score = 0; + for (i = 0; i < face->num_charmaps; ++i) { + FT_Encoding enc_entry = face->charmaps[i]->encoding; + mm_log((2, "i_ft2_new, encoding %lX platform %u encoding %u\n", + enc_entry, face->charmaps[i]->platform_id, + face->charmaps[i]->encoding_id)); + for (j = 0; j < sizeof(enc_scores) / sizeof(*enc_scores); ++j) { + if (enc_scores[j].encoding == enc_entry && enc_scores[j].score > score) { + encoding = enc_entry; + score = enc_scores[j].score; + break; + } + } + } + FT_Select_Charmap(face, encoding); + mm_log((2, "i_ft2_new, selected encoding %lX\n", encoding)); + result = mymalloc(sizeof(FT2_Fonthandle)); result->face = face; result->xdpi = result->ydpi = 72; + result->encoding = encoding; /* by default we disable hinting on a call to i_ft2_settransform() if we don't do this, then the hinting can the untransformed text @@ -122,6 +176,27 @@ i_ft2_new(char *name, int index) { result->matrix[0] = 1; result->matrix[1] = 0; result->matrix[2] = 0; result->matrix[3] = 0; result->matrix[4] = 1; result->matrix[5] = 0; +#ifdef IM_FT2_MM + { + FT_Multi_Master *mm = &result->mm; + int i; + + if ((face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) != 0 + && (error = FT_Get_Multi_Master(face, mm)) == 0) { + mm_log((2, "MM Font, %d axes, %d designs\n", mm->num_axis, mm->num_designs)); + for (i = 0; i < mm->num_axis; ++i) { + mm_log((2, " axis %d name %s range %ld - %ld\n", i, mm->axis[i].name, + (long)(mm->axis[i].minimum), (long)(mm->axis[i].maximum))); + } + result->has_mm = 1; + } + else { + mm_log((2, "No multiple masters\n")); + result->has_mm = 0; + } + } +#endif + return result; } @@ -194,7 +269,7 @@ This should be a 2 x 3 matrix like: =cut */ int -i_ft2_settransform(FT2_Fonthandle *handle, double *matrix) { +i_ft2_settransform(FT2_Fonthandle *handle, const double *matrix) { FT_Matrix m; FT_Vector v; int i; @@ -242,7 +317,7 @@ Returns non-zero on success. */ int i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, - char *text, int len, int *bbox) { + char const *text, int len, int *bbox, int utf8) { FT_Error error; int width; int index; @@ -251,6 +326,8 @@ i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, int glyph_ascent, glyph_descent; FT_Glyph_Metrics *gm; int start = 0; + int loadFlags = FT_LOAD_DEFAULT; + int rightb; mm_log((1, "i_ft2_bbox(handle %p, cheight %f, cwidth %f, text %p, len %d, bbox %p)\n", handle, cheight, cwidth, text, len, bbox)); @@ -262,13 +339,27 @@ i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, i_push_error(0, "setting size"); } + if (!handle->hint) + loadFlags |= FT_LOAD_NO_HINTING; + first = 1; width = 0; - while (len--) { - int c = (unsigned char)*text++; - + while (len) { + unsigned long c; + if (utf8) { + c = i_utf8_advance(&text, &len); + if (c == ~0UL) { + i_push_error(0, "invalid UTF8 character"); + return 0; + } + } + else { + c = (unsigned char)*text++; + --len; + } + index = FT_Get_Char_Index(handle->face, c); - error = FT_Load_Glyph(handle->face, index, FT_LOAD_DEFAULT); + error = FT_Load_Glyph(handle->face, index, loadFlags); if (error) { ft2_push_message(error); i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)", @@ -288,7 +379,7 @@ i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, if (glyph_ascent > ascent) ascent = glyph_ascent; - if (glyph_descent > descent) + if (glyph_descent < descent) descent = glyph_descent; width += gm->horiAdvance / 64; @@ -297,20 +388,25 @@ i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, /* last character handle the case where the right the of the character overlaps the right*/ - int rightb = gm->horiAdvance - gm->horiBearingX - gm->width; - if (rightb < 0) - width -= rightb / 64; + rightb = (gm->horiAdvance - gm->horiBearingX - gm->width)/64; + /*if (rightb > 0) + rightb = 0;*/ } } - bbox[0] = start; - bbox[1] = handle->face->size->metrics.descender / 64; - bbox[2] = width; - bbox[3] = handle->face->size->metrics.ascender / 64; - bbox[4] = descent; - bbox[5] = ascent; - - return 1; + bbox[BBOX_NEG_WIDTH] = start; + bbox[BBOX_GLOBAL_DESCENT] = handle->face->size->metrics.descender / 64; + bbox[BBOX_POS_WIDTH] = width; + if (rightb < 0) + bbox[BBOX_POS_WIDTH] -= rightb; + bbox[BBOX_GLOBAL_ASCENT] = handle->face->size->metrics.ascender / 64; + bbox[BBOX_DESCENT] = descent; + bbox[BBOX_ASCENT] = ascent; + bbox[BBOX_ADVANCE_WIDTH] = width; + bbox[BBOX_RIGHT_BEARING] = rightb; + 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])); + + return BBOX_RIGHT_BEARING + 1; } /* @@ -334,7 +430,6 @@ too much hard work. void ft2_transform_box(FT2_Fonthandle *handle, int bbox[4]) { double work[8]; double *matrix = handle->matrix; - int i; work[0] = matrix[0] * bbox[0] + matrix[1] * bbox[1]; work[1] = matrix[3] * bbox[0] + matrix[4] * bbox[1]; @@ -345,10 +440,10 @@ void ft2_transform_box(FT2_Fonthandle *handle, int bbox[4]) { work[6] = matrix[0] * bbox[2] + matrix[1] * bbox[3]; work[7] = matrix[3] * bbox[2] + matrix[4] * bbox[3]; - bbox[0] = floor(min(min(work[0], work[2]),min(work[4], work[6]))); - bbox[1] = floor(min(min(work[1], work[3]),min(work[5], work[7]))); - bbox[2] = ceil(max(max(work[0], work[2]),max(work[4], work[6]))); - bbox[3] = ceil(max(max(work[1], work[3]),max(work[5], work[7]))); + bbox[0] = floor(i_min(i_min(work[0], work[2]),i_min(work[4], work[6]))); + bbox[1] = floor(i_min(i_min(work[1], work[3]),i_min(work[5], work[7]))); + bbox[2] = ceil(i_max(i_max(work[0], work[2]),i_max(work[4], work[6]))); + bbox[3] = ceil(i_max(i_max(work[1], work[3]),i_max(work[5], work[7]))); } /* @@ -360,10 +455,10 @@ bounding box in bbox[] that encloses both. =cut */ static void expand_bounds(int bbox[4], int bbox2[4]) { - bbox[0] = min(bbox[0], bbox2[0]); - bbox[1] = min(bbox[1], bbox2[1]); - bbox[2] = max(bbox[2], bbox2[2]); - bbox[3] = max(bbox[3], bbox2[3]); + bbox[0] = i_min(bbox[0], bbox2[0]); + bbox[1] = i_min(bbox[1], bbox2[1]); + bbox[2] = i_max(bbox[2], bbox2[2]); + bbox[3] = i_max(bbox[3], bbox2[3]); } /* @@ -388,7 +483,7 @@ Returns non-zero on success. */ int i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, - char *text, int len, int vlayout, int utf8, int *bbox) { + char const *text, int len, int vlayout, int utf8, int *bbox) { FT_Error error; int width; int index; @@ -396,17 +491,17 @@ i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, int ascent = 0, descent = 0; int glyph_ascent, glyph_descent; FT_Glyph_Metrics *gm; - int start = 0; int work[4]; int bounds[4]; double x = 0, y = 0; int i; FT_GlyphSlot slot; - int advx, advy; int loadFlags = FT_LOAD_DEFAULT; if (vlayout) loadFlags |= FT_LOAD_VERTICAL_LAYOUT; + if (!handle->hint) + loadFlags |= FT_LOAD_NO_HINTING; error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64, handle->xdpi, handle->ydpi); @@ -420,7 +515,7 @@ i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, while (len) { unsigned long c; if (utf8) { - c = utf8_advance(&text, &len); + c = i_utf8_advance(&text, &len); if (c == ~0UL) { i_push_error(0, "invalid UTF8 character"); return 0; @@ -480,7 +575,7 @@ i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, } x += slot->advance.x / 64; y += slot->advance.y / 64; - + if (glyph_ascent > ascent) ascent = glyph_ascent; if (glyph_descent > descent) @@ -513,8 +608,6 @@ i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, return 1; } - - static int make_bmp_map(FT_Bitmap *bitmap, unsigned char *map); @@ -536,13 +629,13 @@ Returns non-zero on success. =cut */ int -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, +i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, const i_color *cl, + double cheight, double cwidth, char const *text, int len, int align, int aa, int vlayout, int utf8) { FT_Error error; int index; FT_Glyph_Metrics *gm; - int bbox[6]; + int bbox[BOUNDING_BOX_COUNT]; FT_GlyphSlot slot; int x, y; unsigned char *bmp; @@ -567,7 +660,7 @@ i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl, loadFlags |= FT_LOAD_NO_HINTING; /* set the base-line based on the string ascent */ - if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox)) + if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox, utf8)) return 0; if (!align) { @@ -578,7 +671,7 @@ i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl, while (len) { unsigned long c; if (utf8) { - c = utf8_advance(&text, &len); + c = i_utf8_advance(&text, &len); if (c == ~0UL) { i_push_error(0, "invalid UTF8 character"); return 0; @@ -600,55 +693,57 @@ i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl, slot = handle->face->glyph; gm = &slot->metrics; - error = FT_Render_Glyph(slot, aa ? ft_render_mode_normal : ft_render_mode_mono); - if (error) { - ft2_push_message(error); - i_push_errorf(0, "rendering glyph 0x%04X (character \\x%02X)"); - return 0; - } - if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) { - bmp = slot->bitmap.buffer; - for (y = 0; y < slot->bitmap.rows; ++y) { - int pos = 0; - int bit = 0x80; - for (x = 0; x < slot->bitmap.width; ++x) { - if (bmp[pos] & bit) - i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, cl); - - bit >>= 1; - if (bit == 0) { - bit = 0x80; - ++pos; - } - } - bmp += slot->bitmap.pitch; + if (gm->width) { + error = FT_Render_Glyph(slot, aa ? ft_render_mode_normal : ft_render_mode_mono); + if (error) { + ft2_push_message(error); + i_push_errorf(0, "rendering glyph 0x%04X (character \\x%02X)"); + return 0; } - } - else { - /* grey scale or something we can treat as greyscale */ - /* we create a map to convert from the bitmap values to 0-255 */ - if (last_mode != slot->bitmap.pixel_mode - || last_grays != slot->bitmap.num_grays) { - if (!make_bmp_map(&slot->bitmap, map)) - return 0; - last_mode = slot->bitmap.pixel_mode; - last_grays = slot->bitmap.num_grays; + if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) { + bmp = slot->bitmap.buffer; + for (y = 0; y < slot->bitmap.rows; ++y) { + int pos = 0; + int bit = 0x80; + for (x = 0; x < slot->bitmap.width; ++x) { + if (bmp[pos] & bit) + i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, cl); + + bit >>= 1; + if (bit == 0) { + bit = 0x80; + ++pos; + } + } + bmp += slot->bitmap.pitch; + } } - - bmp = slot->bitmap.buffer; - for (y = 0; y < slot->bitmap.rows; ++y) { - for (x = 0; x < slot->bitmap.width; ++x) { - int value = map[bmp[x]]; - if (value) { - i_gpix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, &pel); - for (ch = 0; ch < im->channels; ++ch) { - pel.channel[ch] = - ((255-value)*pel.channel[ch] + value * cl->channel[ch]) / 255; - } - i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, &pel); - } - } - bmp += slot->bitmap.pitch; + else { + /* grey scale or something we can treat as greyscale */ + /* we create a map to convert from the bitmap values to 0-255 */ + if (last_mode != slot->bitmap.pixel_mode + || last_grays != slot->bitmap.num_grays) { + if (!make_bmp_map(&slot->bitmap, map)) + return 0; + last_mode = slot->bitmap.pixel_mode; + last_grays = slot->bitmap.num_grays; + } + + bmp = slot->bitmap.buffer; + for (y = 0; y < slot->bitmap.rows; ++y) { + for (x = 0; x < slot->bitmap.width; ++x) { + int value = map[bmp[x]]; + if (value) { + i_gpix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, &pel); + for (ch = 0; ch < im->channels; ++ch) { + pel.channel[ch] = + ((255-value)*pel.channel[ch] + value * cl->channel[ch]) / 255; + } + i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, &pel); + } + } + bmp += slot->bitmap.pitch; + } } } @@ -677,8 +772,9 @@ Returns non-zero on success. =cut */ +int 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, + double cheight, double cwidth, char const *text, int len, int align, int aa, int vlayout, int utf8) { int bbox[8]; i_img *work; @@ -730,17 +826,17 @@ Returns the number of characters that were checked. =cut */ -int i_ft2_has_chars(FT2_Fonthandle *handle, char *text, int len, int utf8, - char *out) { +int i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, int len, + int utf8, char *out) { int count = 0; - mm_log((1, "i_ft2_check_chars(handle %p, text %p, len %d, utf8 %d)\n", + mm_log((1, "i_ft2_has_chars(handle %p, text %p, len %d, utf8 %d)\n", handle, text, len, utf8)); while (len) { unsigned long c; int index; if (utf8) { - c = utf8_advance(&text, &len); + c = i_utf8_advance(&text, &len); if (c == ~0UL) { i_push_error(0, "invalid UTF8 character"); return 0; @@ -762,10 +858,10 @@ int i_ft2_has_chars(FT2_Fonthandle *handle, char *text, int len, int utf8, /* uses a method described in fterrors.h to build an error translation function */ -#undef __FT_ERRORS_H__ +#undef __FTERRORS_H__ #define FT_ERRORDEF(e, v, s) case v: i_push_error(code, s); return; -#define FT_ERROR_START_LIST -#define FT_ERROR_END_LIST +#define FT_ERROR_START_LIST +#define FT_ERROR_END_LIST /* =back @@ -824,81 +920,201 @@ make_bmp_map(FT_Bitmap *bitmap, unsigned char *map) { return 1; } -struct utf8_size { - int mask, expect; - int size; -}; +/* FREETYPE_PATCH was introduced in 2.0.6, we don't want a false + positive on 2.0.0 to 2.0.4, so we accept a false negative in 2.0.5 */ +#ifndef FREETYPE_PATCH +#define FREETYPE_PATCH 4 +#endif -struct utf8_size utf8_sizes[] = -{ - { 0x80, 0x00, 1 }, - { 0xE0, 0xC0, 2 }, - { 0xF0, 0xE0, 3 }, - { 0xF8, 0xF0, 4 }, -}; +/* FT_Get_Postscript_Name() was introduced in FT2.0.5 */ +#define IM_HAS_FACE_NAME (FREETYPE_MINOR > 0 || FREETYPE_PATCH >= 5) +/* #define IM_HAS_FACE_NAME 0 */ /* -=item utf8_advance(char **p, int *len) - -Retreive a UTF8 character from the stream. - -Modifies *p and *len to indicate the consumed characters. +=item i_ft2_face_name(handle, name_buf, name_buf_size) -This doesn't support the extended UTF8 encoding used by later versions -of Perl. +Fills the given buffer with the Postscript Face name of the font, +if there is one. =cut */ -unsigned long utf8_advance(char **p, int *len) { - unsigned char c; - int i, ci, clen = 0; - unsigned char codes[3]; - if (*len == 0) - return ~0UL; - c = *(*p)++; --*len; - - for (i = 0; i < sizeof(utf8_sizes)/sizeof(*utf8_sizes); ++i) { - if ((c & utf8_sizes[i].mask) == utf8_sizes[i].expect) { - clen = utf8_sizes[i].size; - } +int +i_ft2_face_name(FT2_Fonthandle *handle, char *name_buf, size_t name_buf_size) { +#if IM_HAS_FACE_NAME + char const *name = FT_Get_Postscript_Name(handle->face); + + i_clear_error(); + + if (name) { + strncpy(name_buf, name, name_buf_size); + name_buf[name_buf_size-1] = '\0'; + + return strlen(name) + 1; } - if (clen == 0 || *len < clen-1) { - --*p; ++*len; - return ~0UL; + else { + i_push_error(0, "no face name available"); + *name_buf = '\0'; + + return 0; } +#else + i_clear_error(); + i_push_error(0, "Freetype 2.0.6 or later required"); + *name_buf = '\0'; - /* check that each character is well formed */ - i = 1; - ci = 0; - while (i < clen) { - if (((*p)[ci] & 0xC0) != 0x80) { - --*p; ++*len; - return ~0UL; - } - codes[ci] = (*p)[ci]; - ++ci; ++i; + return 0; +#endif +} + +int +i_ft2_can_face_name(void) { + return IM_HAS_FACE_NAME; +} + +/* FT_Has_PS_Glyph_Names() was introduced in FT2.1.1 */ +/* well, I assume FREETYPE_MAJOR is 2, since we're here */ +#if FREETYPE_MINOR < 1 || (FREETYPE_MINOR == 1 && FREETYPE_PATCH < 1) +#define FT_Has_PS_Glyph_Names(face) (FT_HAS_GLYPH_NAMES(face)) +#endif + +int +i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned long ch, char *name_buf, + size_t name_buf_size, int reliable_only) { +#ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES + i_clear_error(); + *name_buf = '\0'; + i_push_error(0, "FT2 configured without glyph name support"); + + return 0; +#else + FT_UInt index; + + i_clear_error(); + + if (!FT_HAS_GLYPH_NAMES(handle->face)) { + i_push_error(0, "no glyph names in font"); + *name_buf = '\0'; + return 0; } - *p += clen-1; *len -= clen-1; - if (c & 0x80) { - if ((c & 0xE0) == 0xC0) { - return ((c & 0x1F) << 6) + (codes[0] & 0x3F); - } - else if ((c & 0xF0) == 0xE0) { - return ((c & 0x0F) << 12) | ((codes[0] & 0x3F) << 6) | (codes[1] & 0x3f); + if (reliable_only && !FT_Has_PS_Glyph_Names(handle->face)) { + i_push_error(0, "no reliable glyph names in font - set reliable_only to 0 to try anyway"); + *name_buf = '\0'; + return 0; + } + + index = FT_Get_Char_Index(handle->face, ch); + + if (index) { + FT_Error error = FT_Get_Glyph_Name(handle->face, index, name_buf, + name_buf_size); + if (error) { + ft2_push_message(error); + *name_buf = '\0'; + return 0; } - else if ((c & 0xF8) == 0xF0) { - return ((c & 0x07) << 18) | ((codes[0] & 0x3F) << 12) - | ((codes[1] & 0x3F) << 6) | (codes[2] & 0x3F); + if (*name_buf) { + return strlen(name_buf) + 1; } else { - *p -= clen; *len += clen; - return ~0UL; + return 0; } } else { - return c; + i_push_error(0, "no glyph for that character"); + *name_buf = 0; + return 0; + } +#endif +} + +int +i_ft2_can_do_glyph_names(void) { +#ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES + return 0; +#else + return 1; +#endif +} + +int +i_ft2_face_has_glyph_names(FT2_Fonthandle *handle) { +#ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES + return 0; +#else + return FT_Has_PS_Glyph_Names(handle->face); +#endif +} + +int +i_ft2_is_multiple_master(FT2_Fonthandle *handle) { + i_clear_error(); +#ifdef IM_FT2_MM + return handle->has_mm; +#else + return 0; +#endif +} + +int +i_ft2_get_multiple_masters(FT2_Fonthandle *handle, i_font_mm *mm) { +#ifdef IM_FT2_MM + int i; + FT_Multi_Master *mms = &handle->mm; + + i_clear_error(); + if (!handle->has_mm) { + i_push_error(0, "Font has no multiple masters"); + return 0; + } + mm->num_axis = mms->num_axis; + mm->num_designs = mms->num_designs; + for (i = 0; i < mms->num_axis; ++i) { + mm->axis[i].name = mms->axis[i].name; + mm->axis[i].minimum = mms->axis[i].minimum; + mm->axis[i].maximum = mms->axis[i].maximum; + } + + return 1; +#else + i_clear_error(); + i_push_error(0, "Multiple master functions unavailable"); + return 0; +#endif +} + +int +i_ft2_set_mm_coords(FT2_Fonthandle *handle, int coord_count, const long *coords) { +#ifdef IM_FT2_MM + int i; + FT_Long ftcoords[T1_MAX_MM_AXIS]; + FT_Error error; + + i_clear_error(); + if (!handle->has_mm) { + i_push_error(0, "Font has no multiple masters"); + return 0; + } + if (coord_count != handle->mm.num_axis) { + i_push_error(0, "Number of MM coords doesn't match MM axis count"); + return 0; + } + for (i = 0; i < coord_count; ++i) + ftcoords[i] = coords[i]; + + error = FT_Set_MM_Design_Coordinates(handle->face, coord_count, ftcoords); + if (error) { + ft2_push_message(error); + return 0; } + + return 1; +#else + i_clear_error(); + i_push_error(0, "Multiple master functions unavailable"); + + return 0; +#endif } /*