]> git.imager.perl.org - imager.git/blobdiff - FT2/freetyp2.c
i_img_info() (C API) no longer tries to handle a NULL image object pointer.
[imager.git] / FT2 / freetyp2.c
index c1e6ed540ae34075c859be0076a7e344f27cdffb..6ee45d7973e12de78c984149675cd483216f8d7c 100644 (file)
@@ -17,7 +17,7 @@ freetyp2.c - font support via the FreeType library version 2.
   i_img *im = ...;
   i_color cl;
   if (!i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, length, align,
-                  aa)) { error }
+                  aa, vlayout, utf8)) { error }
   if (!i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, length,
                 align, aa)) { error }
   i_ft2_destroy(font);
@@ -38,6 +38,7 @@ Truetype, Type1 and Windows FNT.
 #include "imft2.h"
 #include <stdio.h>
 #include <math.h>
+#include <string.h>
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #ifdef FT_MULTIPLE_MASTERS_H
@@ -59,13 +60,49 @@ typedef struct {
   im_context_t ctx;
 } ft2_state;
 
+static ft2_state *
+i_ft2_init(void);
+
 static i_img_dim i_min(i_img_dim a, i_img_dim b);
 static i_img_dim i_max(i_img_dim a, i_img_dim b);
 
+int
+i_ft2_version(int runtime, char *buf, size_t buf_size) {
+  char work[100];
+
+  i_clear_error();
+
+  if (buf_size == 0) {
+    i_push_error(0, "zero size buffer supplied");
+    return 0;
+  }
+  if (runtime) {
+    ft2_state *ft2;
+    /* initialized to work around a bug in FT2
+       http://lists.nongnu.org/archive/html/freetype-devel/2002-09/msg00058.html
+       Though I don't know why I still see this in 2.4.2
+     */
+    FT_Int major = 1, minor = 1, patch = 1;
+
+    if ((ft2 = i_ft2_init()) == NULL)
+      return 0;
+
+    FT_Library_Version(ft2->library, &major, &minor, &patch);
+    sprintf(work, "%d.%d.%d", (int)major, (int)minor, (int)patch);
+  }
+  else {
+    sprintf(work, "%d.%d.%d", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
+  }
+  strncpy(buf, work, buf_size);
+  buf[buf_size-1] = '\0';
+
+  return 1;
+}
+
 void
 i_ft2_start(void) {
   if (slot == -1)
-    slot = im_context_slot_new(ft2_final, "FT2");
+    slot = im_context_slot_new(ft2_final);
 }
 
 /*
@@ -202,8 +239,8 @@ i_ft2_new(const char *name, int index) {
   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,
+    mm_log((2, "i_ft2_new, encoding %X platform %u encoding %u\n",
+            (unsigned)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) {
@@ -214,7 +251,7 @@ i_ft2_new(const char *name, int index) {
     }
   }
   FT_Select_Charmap(face, encoding);
-  mm_log((2, "i_ft2_new, selected encoding %lX\n", encoding));
+  mm_log((2, "i_ft2_new, selected encoding %X\n", (unsigned)encoding));
 
   result = mymalloc(sizeof(FT2_Fonthandle));
   result->face = face;
@@ -387,8 +424,10 @@ i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth,
   int loadFlags = FT_LOAD_DEFAULT;
   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));
+  i_clear_error();
+
+  mm_log((1, "i_ft2_bbox(handle %p, cheight %f, cwidth %f, text %p, len %u, bbox %p)\n",
+         handle, cheight, cwidth, text, (unsigned)len, bbox));
 
   error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64, 
                            handle->xdpi, handle->ydpi);
@@ -420,7 +459,7 @@ i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth,
     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)", 
+      i_push_errorf(0, "loading glyph for character \\x%02lx (glyph 0x%04X)", 
                     c, index);
       return 0;
     }
@@ -462,7 +501,11 @@ i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth,
   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]));
+  mm_log((1, " bbox=> negw=%" i_DF " glob_desc=%" i_DF " pos_wid=%" i_DF
+         " glob_asc=%" i_DF " desc=%" i_DF " asc=%" i_DF " adv_width=%" i_DF
+         " rightb=%" i_DF "\n",
+         i_DFc(bbox[0]), i_DFc(bbox[1]), i_DFc(bbox[2]), i_DFc(bbox[3]),
+         i_DFc(bbox[4]), i_DFc(bbox[5]), i_DFc(bbox[6]), i_DFc(bbox[7])));
 
   return BBOX_RIGHT_BEARING + 1;
 }
@@ -543,14 +586,13 @@ int
 i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, 
            char const *text, size_t len, int vlayout, int utf8, i_img_dim *bbox) {
   FT_Error error;
-  i_img_dim width;
   int index;
   int first;
   i_img_dim ascent = 0, descent = 0;
   int glyph_ascent, glyph_descent;
   FT_Glyph_Metrics *gm;
   i_img_dim work[4];
-  i_img_dim bounds[4];
+  i_img_dim bounds[4] = { 0 };
   double x = 0, y = 0;
   int i;
   FT_GlyphSlot slot;
@@ -569,7 +611,6 @@ i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth,
   }
 
   first = 1;
-  width = 0;
   while (len) {
     unsigned long c;
     if (utf8) {
@@ -588,7 +629,7 @@ i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth,
     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)", 
+      i_push_errorf(0, "loading glyph for character \\x%02lx (glyph 0x%04X)",
                     c, index);
       return 0;
     }
@@ -696,15 +737,20 @@ i_ft2_text(FT2_Fonthandle *handle, i_img *im, i_img_dim tx, i_img_dim ty, const
   i_img_dim bbox[BOUNDING_BOX_COUNT];
   FT_GlyphSlot slot;
   int x, y;
-  unsigned char *bmp;
   unsigned char map[256];
   char last_mode = ft_pixel_mode_none; 
   int last_grays = -1;
   int loadFlags = FT_LOAD_DEFAULT;
-  i_render *render;
+  i_render *render = NULL;
+  unsigned char *work_bmp = NULL;
+  size_t work_bmp_size = 0;
 
-  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));
+  mm_log((1, "i_ft2_text(handle %p, im %p, (tx,ty) (" i_DFp "), cl %p (#%02x%02x%02x%02x), cheight %f, cwidth %f, text %p, len %u, align %d, aa %d, vlayout %d, utf8 %d)\n",
+         handle, im, i_DFcp(tx, ty), cl, cl->rgba.r, cl->rgba.g, cl->rgba.b,
+         cl->rgba.a, cheight, cwidth, text, (unsigned)len, align, aa,
+         vlayout, utf8));
+
+  i_clear_error();
 
   if (vlayout) {
     if (!FT_HAS_VERTICAL(handle->face)) {
@@ -720,8 +766,10 @@ i_ft2_text(FT2_Fonthandle *handle, i_img *im, i_img_dim tx, i_img_dim ty, const
   if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox, utf8))
     return 0;
 
-  if (aa)
-    render = i_render_new(im, bbox[BBOX_POS_WIDTH] - bbox[BBOX_NEG_WIDTH]);
+  render = i_render_new(im, bbox[BBOX_POS_WIDTH] - bbox[BBOX_NEG_WIDTH]);
+
+  work_bmp_size = bbox[BBOX_POS_WIDTH] - bbox[BBOX_NEG_WIDTH];
+  work_bmp = mymalloc(work_bmp_size);
 
   if (!align) {
     /* this may need adjustment */
@@ -746,9 +794,9 @@ i_ft2_text(FT2_Fonthandle *handle, i_img *im, i_img_dim tx, i_img_dim ty, const
     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)", 
+      i_push_errorf(0, "loading glyph for character \\x%02lx (glyph 0x%04X)",
                     c, index);
-      if (aa)
+      if (render)
         i_render_delete(render);
       return 0;
     }
@@ -759,30 +807,39 @@ i_ft2_text(FT2_Fonthandle *handle, i_img *im, i_img_dim tx, i_img_dim ty, const
       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_delete(render);
+       i_push_errorf(0, "rendering glyph 0x%04lX (character \\x%02X)", c, index);
+       if (render)
+         i_render_delete(render);
        return 0;
       }
       if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) {
-       bmp = slot->bitmap.buffer;
+       unsigned char *bmp = slot->bitmap.buffer;
+       if (work_bmp_size < slot->bitmap.width) {
+         work_bmp_size = slot->bitmap.width;
+         work_bmp =  myrealloc(work_bmp, work_bmp_size);
+       }
        for (y = 0; y < slot->bitmap.rows; ++y) {
          int pos = 0;
          int bit = 0x80;
+         unsigned char *p = work_bmp;
          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);
-           
+           *p++ = (bmp[pos] & bit) ? 0xff : 0;
+
            bit >>= 1;
            if (bit == 0) {
              bit = 0x80;
              ++pos;
            }
          }
+          i_render_color(render, tx + slot->bitmap_left, ty-slot->bitmap_top+y,
+                         slot->bitmap.width, work_bmp, cl);
+
          bmp += slot->bitmap.pitch;
        }
       }
       else {
+       unsigned char *bmp = slot->bitmap.buffer;
+
        /* 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 
@@ -793,7 +850,6 @@ i_ft2_text(FT2_Fonthandle *handle, i_img *im, i_img_dim tx, i_img_dim ty, const
          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) {
@@ -811,14 +867,17 @@ i_ft2_text(FT2_Fonthandle *handle, i_img *im, i_img_dim tx, i_img_dim ty, const
     ty -= slot->advance.y / 64;
   }
 
-  if (aa)
+  if (render)
     i_render_delete(render);
 
+  if (work_bmp)
+    myfree(work_bmp);
+
   return 1;
 }
 
 /*
-=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)
+=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, int vlayout, int utf8)
 
 Renders I<text> to (I<tx>, I<ty>) in I<im> to I<channel> at the given 
 I<cheight> and I<cwidth>.
@@ -828,7 +887,9 @@ first character at (I<tx>, I<ty>).  If align is non-zero then the text
 is rendered with (I<tx>, I<ty>) aligned with the base-line of the
 characters.
 
-If aa is non-zero then the text is anti-aliased.
+If C<utf8> is non-zero the text is treated as UTF-8 encoded
+
+If C<aa> is non-zero then the text is drawn anti-aliased.
 
 Returns non-zero on success.
 
@@ -841,11 +902,14 @@ i_ft2_cp(FT2_Fonthandle *handle, i_img *im, i_img_dim tx, i_img_dim ty, int chan
          int aa, int vlayout, int utf8) {
   i_img_dim bbox[8];
   i_img *work;
-  i_color cl, cl2;
-  int x, y;
+  i_color cl;
+  int y;
+  unsigned char *bmp;
+
+  mm_log((1, "i_ft2_cp(handle %p, im %p, (tx, ty) (" i_DFp "), channel %d, cheight %f, cwidth %f, text %p, len %u, align %d, aa %d, vlayout %d, utf8 %d)\n", 
+         handle, im, i_DFcp(tx, ty), channel, cheight, cwidth, text, (unsigned)len, align, aa, vlayout, utf8));
 
-  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", 
-         handle, im, tx, ty, channel, cheight, cwidth, text, len));
+  i_clear_error();
 
   if (vlayout && !FT_HAS_VERTICAL(handle->face)) {
     i_push_error(0, "face has no vertical metrics");
@@ -857,6 +921,9 @@ i_ft2_cp(FT2_Fonthandle *handle, i_img *im, i_img_dim tx, i_img_dim ty, int chan
 
   work = i_img_8_new(bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, 1);
   cl.channel[0] = 255;
+  cl.channel[1] = 255;
+  cl.channel[2] = 255;
+  cl.channel[3] = 255;
   if (!i_ft2_text(handle, work, -bbox[0], -bbox[1], &cl, cheight, cwidth, 
                   text, len, 1, aa, vlayout, utf8))
     return 0;
@@ -868,14 +935,13 @@ i_ft2_cp(FT2_Fonthandle *handle, i_img *im, i_img_dim tx, i_img_dim ty, int chan
   
   /* render to the specified channel */
   /* this will be sped up ... */
+  bmp = mymalloc(work->xsize);
   for (y = 0; y < work->ysize; ++y) {
-    for (x = 0; x < work->xsize; ++x) {
-      i_gpix(work, x, y, &cl);
-      i_gpix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
-      cl2.channel[channel] = cl.channel[0];
-      i_ppix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
-    }
+    i_gsamp(work, 0, work->xsize, y, bmp, NULL, 1);
+    i_psamp(im, tx + bbox[0], tx + bbox[0] + work->xsize,
+           ty + y + bbox[1], bmp, &channel, 1);
   }
+  myfree(bmp);
   i_img_destroy(work);
   return 1;
 }
@@ -893,8 +959,10 @@ size_t
 i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, size_t len, 
                     int utf8, char *out) {
   int count = 0;
-  mm_log((1, "i_ft2_has_chars(handle %p, text %p, len %d, utf8 %d)\n", 
-         handle, text, len, utf8));
+  mm_log((1, "i_ft2_has_chars(handle %p, text %p, len %u, utf8 %d)\n", 
+         handle, text, (unsigned)len, utf8));
+
+  i_clear_error();
 
   while (len) {
     unsigned long c;
@@ -1087,6 +1155,10 @@ i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned long ch, char *name_buf,
       *name_buf = '\0';
       return 0;
     }
+    if (strcmp(name_buf, ".notdef") == 0) {
+      *name_buf = 0;
+      return 0;
+    }
     if (*name_buf) {
       return strlen(name_buf) + 1;
     }
@@ -1095,7 +1167,6 @@ i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned long ch, char *name_buf,
     }
   }
   else {
-    i_push_error(0, "no glyph for that character");
     *name_buf = 0;
     return 0;
   }
@@ -1116,7 +1187,8 @@ 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);
+  return FT_HAS_GLYPH_NAMES(handle->face);
+  /* return FT_Has_PS_Glyph_Names(handle->face);*/
 #endif
 }