=cut
*/
-#include "image.h"
+#include "imager.h"
#include <stdio.h>
#include <ft2build.h>
#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 int ft2_initialized = 0;
static FT_Library library;
/*
i_push_error(0, "Initializing Freetype2");
return 0;
}
+
+ ft2_initialized = 1;
+
return 1;
}
/* 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 */
*/
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));
+ if (!ft2_initialized && !i_ft2_init())
+ return NULL;
+
i_clear_error();
error = FT_New_Face(library, name, index, &face);
if (error) {
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;
}
=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;
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));
/* 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;
}
/*
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];
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)
=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;
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));
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];
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;
+ }
}
}
ty -= slot->advance.y / 64;
}
+ if (aa)
+ i_render_done(&render);
+
return 1;
}
=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) {
if (error) {
ft2_push_message(error);
*name_buf = '\0';
- return;
+ return 0;
}
if (*name_buf) {
return strlen(name_buf) + 1;
#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