]> git.imager.perl.org - imager.git/blobdiff - freetyp2.c
look at the correct %Config library and include paths
[imager.git] / freetyp2.c
index 8d202d55b3bb7db52bcbdaf90aa002d2ae894b18..d2e3c0695d6fad151ab334b963dffe7a91fa0416 100644 (file)
@@ -34,13 +34,20 @@ Truetype, Type1 and Windows FNT.
 =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;
 
 /*
@@ -63,6 +70,9 @@ i_ft2_init(void) {
     i_push_error(0, "Initializing Freetype2");
     return 0;
   }
+
+  ft2_initialized = 1;
+
   return 1;
 }
 
@@ -74,6 +84,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,18 +126,19 @@ 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));
 
+  if (!ft2_initialized && !i_ft2_init())
+    return NULL;
+
   i_clear_error();
   error = FT_New_Face(library, name, index, &face);
   if (error) {
@@ -166,6 +183,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 +276,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 +334,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 +395,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 +437,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 +498,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 +636,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 +649,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 +669,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 +697,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 +760,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 +784,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 +870,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 +991,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 +1000,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 +1058,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