X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/ea9e6c3f3c5a1474664d5407701cf736fcb39a09..a1bd25234d6faee6a2495b134762f08a772626c5:/freetyp2.c diff --git a/freetyp2.c b/freetyp2.c index 8d202d55..d0409970 100644 --- a/freetyp2.c +++ b/freetyp2.c @@ -34,10 +34,16 @@ 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); @@ -74,6 +80,12 @@ struct FT2_Fonthandle { /* 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 */ @@ -110,12 +122,10 @@ 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; @@ -166,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; } @@ -238,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; @@ -296,7 +327,7 @@ i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, FT_Glyph_Metrics *gm; int start = 0; int loadFlags = FT_LOAD_DEFAULT; - int rightb; + int rightb = 0; 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)); @@ -357,21 +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*/ - rightb = gm->horiAdvance - gm->horiBearingX - gm->width; - if (rightb > 0) - rightb = 0; + rightb = (gm->horiAdvance - gm->horiBearingX - gm->width)/64; + /*if (rightb > 0) + rightb = 0;*/ } } bbox[BBOX_NEG_WIDTH] = start; bbox[BBOX_GLOBAL_DESCENT] = handle->face->size->metrics.descender / 64; - bbox[BBOX_POS_WIDTH] = width - rightb; + 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_ADVANCE_WIDTH + 1; + return BBOX_RIGHT_BEARING + 1; } /* @@ -395,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]; @@ -457,13 +491,11 @@ 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) @@ -597,7 +629,7 @@ Returns non-zero on success. =cut */ int -i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl, +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; @@ -610,9 +642,8 @@ i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl, unsigned char map[256]; char last_mode = ft_pixel_mode_none; int last_grays = -1; - int ch; - i_color pel; int loadFlags = FT_LOAD_DEFAULT; + i_render render; 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", handle, im, tx, ty, cl, cheight, cwidth, text, align, aa)); @@ -631,6 +662,9 @@ i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl, if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox, utf8)) return 0; + if (aa) + i_render_init(&render, im, bbox[BBOX_POS_WIDTH] - bbox[BBOX_NEG_WIDTH]); + if (!align) { /* this may need adjustment */ tx -= bbox[0] * handle->matrix[0] + bbox[5] * handle->matrix[1] + handle->matrix[2]; @@ -656,60 +690,62 @@ i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl, ft2_push_message(error); i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)", c, index); + if (aa) + i_render_done(&render); return 0; } 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)"); + if (aa) + i_render_done(&render); + 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); + 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) { + if (last_mode == ft_pixel_mode_grays && + last_grays != 255) { + for (x = 0; x < slot->bitmap.width; ++x) + bmp[x] = map[bmp[x]]; } - } - bmp += slot->bitmap.pitch; + i_render_color(&render, tx + slot->bitmap_left, ty-slot->bitmap_top+y, + slot->bitmap.width, bmp, cl); + bmp += slot->bitmap.pitch; + } } } @@ -717,6 +753,9 @@ i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl, ty -= slot->advance.y / 64; } + if (aa) + i_render_done(&render); + return 1; } @@ -738,6 +777,7 @@ 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 const *text, int len, int align, int aa, int vlayout, int utf8) { @@ -823,10 +863,10 @@ int i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, int len, /* 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 @@ -944,8 +984,8 @@ i_ft2_can_face_name(void) { #endif int -i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned char ch, char *name_buf, - size_t name_buf_size) { +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'; @@ -953,35 +993,41 @@ i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned char ch, char *name_buf, return 0; #else + FT_UInt index; + i_clear_error(); - if (FT_Has_PS_Glyph_Names(handle->face)) { - FT_UInt index = FT_Get_Char_Index(handle->face, ch); + if (!FT_HAS_GLYPH_NAMES(handle->face)) { + i_push_error(0, "no glyph names in font"); + *name_buf = '\0'; + return 0; + } + 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; + } - 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; - } - if (*name_buf) { - return strlen(name_buf) + 1; - } - else { - 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; + } + if (*name_buf) { + return strlen(name_buf) + 1; } else { - i_push_error(0, "no glyph for that character"); - *name_buf = 0; return 0; } } else { - i_push_error(0, "no glyph names in font"); - *name_buf = '\0'; + i_push_error(0, "no glyph for that character"); + *name_buf = 0; return 0; } #endif @@ -1005,6 +1051,77 @@ i_ft2_face_has_glyph_names(FT2_Fonthandle *handle) { #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 +} + /* =back