]> git.imager.perl.org - imager.git/blobdiff - freetyp2.c
Fixed r= instead of r=> in 4 places!
[imager.git] / freetyp2.c
index 507078430803fa3ac41891df5e7cfcda283e7f57..0b23791034d4f5ab70ae9e37d8099b782779c458 100644 (file)
@@ -13,7 +13,7 @@ freetyp2.c - font support via the FreeType library version 2.
   double matrix[6];
   if (!i_ft2_settransform(font, matrix)) { error }
   int bbox[6];
-  if (!i_ft2_bbox(font, cheight, cwidth, text, length, bbox)) { error }
+  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,
@@ -40,7 +40,6 @@ Truetype, Type1 and Windows FNT.
 #include FT_FREETYPE_H
 
 static void ft2_push_message(int code);
-static unsigned long utf8_advance(char **p, int *len);
 
 static FT_Library library;
 
@@ -71,11 +70,33 @@ 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];
 };
 
+/* 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 },
+};
+
 /*
 =item i_ft2_new(char *name, int index)
 
@@ -95,6 +116,11 @@ i_ft2_new(char *name, int index) {
   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));
 
   i_clear_error();
   error = FT_New_Face(library, name, index, &face);
@@ -104,9 +130,28 @@ i_ft2_new(char *name, int index) {
     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
@@ -240,7 +285,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;
@@ -250,6 +295,9 @@ i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth,
   FT_Glyph_Metrics *gm;
   int start = 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));
+
   error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64, 
                            handle->xdpi, handle->ydpi);
   if (error) {
@@ -259,9 +307,20 @@ i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth,
 
   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);
     if (error) {
@@ -283,7 +342,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;
@@ -340,10 +399,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])));
 }
 
 /*
@@ -355,10 +414,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]);
 }
 
 /*
@@ -383,7 +442,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;
@@ -415,7 +474,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;
@@ -532,7 +591,7 @@ Returns non-zero on success.
 */
 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,
+           double cheight, double cwidth, char const *text, int len, int align,
            int aa, int vlayout, int utf8) {
   FT_Error error;
   int index;
@@ -548,6 +607,9 @@ i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl,
   i_color pel;
   int loadFlags = FT_LOAD_DEFAULT;
 
+  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 (vlayout) {
     if (!FT_HAS_VERTICAL(handle->face)) {
       i_push_error(0, "face has no vertical metrics");
@@ -559,7 +621,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) {
@@ -570,7 +632,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;
@@ -670,13 +732,16 @@ Returns non-zero on success.
 */
 
 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;
   i_color cl, cl2;
   int x, y;
 
+  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));
+
   if (vlayout && !FT_HAS_VERTICAL(handle->face)) {
     i_push_error(0, "face has no vertical metrics");
     return 0;
@@ -706,10 +771,48 @@ i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, int channel,
       i_ppix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
     }
   }
-
+  i_img_destroy(work);
   return 1;
 }
 
+/*
+=item i_ft2_has_chars(handle, char *text, int len, int utf8, char *out)
+
+Check if the given characters are defined by the font.
+
+Returns the number of characters that were checked.
+
+=cut
+*/
+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_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 = 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);
+    *out++ = index != 0;
+    ++count;
+  }
+
+  return count;
+}
+
 /* uses a method described in fterrors.h to build an error translation
    function
 */
@@ -775,83 +878,6 @@ make_bmp_map(FT_Bitmap *bitmap, unsigned char *map) {
   return 1;
 }
 
-struct utf8_size {
-  int mask, expect;
-  int size;
-};
-
-struct utf8_size utf8_sizes[] =
-{
-  { 0x80, 0x00, 1 },
-  { 0xE0, 0xC0, 2 },
-  { 0xF0, 0xE0, 3 },
-  { 0xF8, 0xF0, 4 },
-};
-
-/*
-=item utf8_advance(char **p, int *len)
-
-Retreive a UTF8 character from the stream.
-
-Modifies *p and *len to indicate the consumed characters.
-
-This doesn't support the extended UTF8 encoding used by later versions
-of Perl.
-
-=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;
-    }
-  }
-  if (clen == 0 || *len < clen-1) {
-    --*p; ++*len;
-    return ~0UL;
-  }
-
-  /* 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;
-  }
-  *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);
-    }
-    else if ((c & 0xF8) == 0xF0) {
-      return ((c & 0x07) << 18) | ((codes[0] & 0x3F) << 12) 
-              | ((codes[1] & 0x3F) << 6) | (codes[2] & 0x3F);
-    }
-    else {
-      *p -= clen; *len += clen;
-      return ~0UL;
-    }
-  }
-  else {
-    return c;
-  }
-}
-
 /*
 =back