even more memleak fixes
[swftools.git] / lib / gfxfont.c
index 893dd18..efe29c3 100644 (file)
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
+#include "../config.h"
 #include "gfxdevice.h"
 #include "gfxtools.h"
+#include "gfxfont.h"
 
 static int loadfont_scale = 64;
-static int skip_unused = 0;
 static int full_unicode = 1;
 
 #ifdef HAVE_FREETYPE
@@ -60,7 +61,7 @@ typedef struct _gfxdrawinfo_t {
     double quality;
 } gfxdrawinfo_t;
 
-static int ft_move_to(FT_Vector* _to, void* user) 
+static int ft_move_to(const FT_Vector* _to, void* user) 
 {
     gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
     gfxdrawer_t* draw = info->draw;
@@ -69,7 +70,7 @@ static int ft_move_to(FT_Vector* _to, void* user)
     draw->moveTo(draw, x,y);
     return 0;
 }
-static int ft_line_to(FT_Vector* _to, void* user) 
+static int ft_line_to(const FT_Vector* _to, void* user) 
 {
     gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
     gfxdrawer_t* draw = info->draw;
@@ -78,7 +79,7 @@ static int ft_line_to(FT_Vector* _to, void* user)
     draw->lineTo(draw, x,y);
     return 0;
 }
-static int ft_cubic_to(FT_Vector* _c1, FT_Vector* _c2, FT_Vector* _to, void* user)
+static int ft_cubic_to(const FT_Vector* _c1, const FT_Vector* _c2, const FT_Vector* _to, void* user)
 {
     gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
     gfxdrawer_t* draw = info->draw;
@@ -91,7 +92,7 @@ static int ft_cubic_to(FT_Vector* _c1, FT_Vector* _c2, FT_Vector* _to, void* use
     gfxdraw_cubicTo(draw, c1x, c1y, c2x, c2y, tox, toy, info->quality);
     return 0;
 }
-static int ft_conic_to(FT_Vector* _c, FT_Vector* _to, void* user) 
+static int ft_conic_to(const FT_Vector* _c, const FT_Vector* _to, void* user) 
 {
     gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
     gfxdrawer_t* draw = info->draw;
@@ -129,43 +130,32 @@ static void glyph_clear(gfxglyph_t*g)
 {
     gfxline_t*line;
     if(g->name) {
-       free(g->name); g->name = 0;
+       free((void*)g->name); g->name = 0;
     }
     gfxline_free(g->line);g->line = 0;
 }
 
-void gfxfont_free(gfxfont_t*font)
-{
-    int t;
-    for(t=0;t<font->num_glyphs;t++) {
-       glyph_clear(&font->glyphs[t]);
-    }
-    if(font->glyphs) {
-       free(font->glyphs);font->glyphs = 0;
-    }
-    font->num_glyphs = 0;
-    if(font->unicode2glyph) {
-       free(font->unicode2glyph);font->unicode2glyph = 0;
-    }
-    free(font);
-}
+static int errorno = 0;
+
+//#define DEBUG 1
 
-gfxfont_t* gfxfont_load(char*filename, double quality)
+gfxfont_t* gfxfont_load(char*id, char*filename, unsigned int flags, double quality)
 {
     FT_Face face;
     FT_Error error;
-    const char* name = 0;
+    const char* fontname = 0;
     FT_ULong charcode;
     FT_UInt gindex;
     gfxfont_t* font;
     int t;
     int*glyph2glyph = 0;
     int*glyph2unicode = 0;
-    FT_Size size;
     int max_unicode = 0;
     int charmap = -1;
     int isunicode = 1;
-   
+    int has_had_errors = 0;
+    int num_names = 0;
+
     if(ftlibrary == 0) {
        if(FT_Init_FreeType(&ftlibrary)) {
            fprintf(stderr, "Couldn't init freetype library!\n");
@@ -174,39 +164,54 @@ gfxfont_t* gfxfont_load(char*filename, double quality)
     }
     error = FT_New_Face(ftlibrary, filename, 0, &face);
     FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
+#ifdef DEBUG
+    printf("gfxfont_load(%s, %s, %f)\n", id, filename, quality);
+#endif
 
     if(error) {
-       fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
+       fprintf(stderr, "Couldn't load file %s- not a TTF file? (error=%02x)\n", filename, error);
        return 0;
     }
     if(face->num_glyphs <= 0) {
-       fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
+       fprintf(stderr, "File %s contains %d glyphs\n", filename, (int)face->num_glyphs);
        return 0;
     }
 
-    font = rfx_calloc(sizeof(gfxfont_t));
+    font = (gfxfont_t*)rfx_calloc(sizeof(gfxfont_t));
     //font->style =  ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0) |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
     //font->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
     //font->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
     //font->leading = font->layout->ascent + font->layout->descent;
     //font->encoding = FONT_ENCODING_UNICODE;
     font->max_unicode = 0;
+    font->id = strdup(id);
     
-    font->glyphs = rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t));
-    glyph2unicode = rfx_calloc(face->num_glyphs*sizeof(int));
-    glyph2glyph = rfx_calloc(face->num_glyphs*sizeof(int));
+    font->glyphs = (gfxglyph_t*)rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t));
+    glyph2unicode = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
+    glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
 
     if(FT_HAS_GLYPH_NAMES(face)) {
        //font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
     }
 
-    /*name = FT_Get_Postscript_Name(face);
-    if(name && *name)
-       font->name = strdup(name);*/
+    fontname = FT_Get_Postscript_Name(face);
+
+#ifdef DEBUG
+    for(t=0;t<face->num_charmaps;t++) {
+        printf("possible encoding: %c%c%c%c (%d of %d)\n", 
+                (face->charmaps[t]->encoding >> 24)&255,
+                (face->charmaps[t]->encoding >> 16)&255,
+                (face->charmaps[t]->encoding >> 8)&255,
+                (face->charmaps[t]->encoding >> 0)&255,
+                t+1, face->num_charmaps
+                );
+    }
+#endif
 
     while(1) 
     {
        charcode = FT_Get_First_Char(face, &gindex);
+
        while(gindex != 0)
        {
            if(gindex >= 0 && gindex<face->num_glyphs) {
@@ -220,27 +225,45 @@ gfxfont_t* gfxfont_load(char*filename, double quality)
            charcode = FT_Get_Next_Char(face, charcode, &gindex);
        }
 
+#ifdef DEBUG
+        if(face->charmap) {
+            printf("ENCODING: %c%c%c%c (%d of %d) max_unicode=%d\n", 
+                    (face->charmap->encoding >> 24)&255,
+                    (face->charmap->encoding >> 16)&255,
+                    (face->charmap->encoding >> 8)&255,
+                    (face->charmap->encoding >> 0)&255,
+                    charmap, face->num_charmaps, font->max_unicode
+                    );
+        } else {
+            printf("ENCODING: NONE (%d of %d) max_unicode=%d\n",
+                    charmap, face->num_charmaps, font->max_unicode
+                    );
+        }
+#endif
+
        /* if we didn't find a single encoding character, try
           the font's charmaps instead. That usually means that
           the encoding is no longer unicode. 
           TODO: find a way to convert the encoding to unicode
         */
-       if(font->max_unicode == 0 && charmap < face->num_charmaps - 1) {
+       if(font->max_unicode == 0 && charmap < face->num_charmaps-1
+               && face->charmaps[charmap+1]->encoding != 0x41444243 /* adbc, custom */
+               && face->charmaps[charmap+1]->encoding != 0x61726d6e    /* armn */
+                )
+               {
            charmap++;
            FT_Set_Charmap(face, face->charmaps[charmap]);
-           //font->encoding = 0;//anything but unicode FIXME
            isunicode = 0;
-       } else 
+       } else
            break;
     }
-
     /* TODO: if isunicode is 1, we now need to permutate the character
              order so that each character is at it's encoding position */
 
     if(full_unicode)
        font->max_unicode = 65535;
     
-    font->unicode2glyph = rfx_calloc(font->max_unicode*sizeof(int));
+    font->unicode2glyph = (int*)rfx_calloc(font->max_unicode*sizeof(int));
     
     for(t=0;t<font->max_unicode;t++) {
        int g = FT_Get_Char_Index(face, t);
@@ -248,6 +271,9 @@ gfxfont_t* gfxfont_load(char*filename, double quality)
            g = -1;
        font->unicode2glyph[t] = g;
        if(g>=0) {
+#ifdef DEBUG
+           printf("u%d ->%d\n", t, g);
+#endif
            max_unicode = t+1;
            if(!glyph2unicode[g]) {
                glyph2unicode[g] = t;
@@ -258,88 +284,141 @@ gfxfont_t* gfxfont_load(char*filename, double quality)
 
     font->num_glyphs = 0;
 
+
+    for(t=0; t < face->num_glyphs; t++) {
+       if(FT_HAS_GLYPH_NAMES(face)) {
+           char name[128];
+           error = FT_Get_Glyph_Name(face, t, name, 127);
+           if(!error && name[0] && !strstr(name, "notdef")) {
+               num_names++;
+           }
+       }
+    }
+
+
     for(t=0; t < face->num_glyphs; t++) {
        FT_Glyph glyph;
-       FT_BBox bbox;
-       FT_Matrix matrix;
        char name[128];
        gfxdrawer_t draw;
        gfxdrawinfo_t info;
-       int ret;
        char hasname = 0;
+       int omit = 0;
        name[0]=0;
-       if(FT_HAS_GLYPH_NAMES(face)) {
+       
+       font->glyphs[font->num_glyphs].advance = 0;
+       font->glyphs[font->num_glyphs].line = 0;
+       font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
+       font->glyphs[font->num_glyphs].name = 0;
+
+       if(FT_HAS_GLYPH_NAMES(face) && (num_names >= face->num_glyphs/10 || num_names > 2)) {
+           name[0] = 0;
            error = FT_Get_Glyph_Name(face, t, name, 127);
            if(!error && name[0] && !strstr(name, "notdef")) {
                font->glyphs[font->num_glyphs].name = strdup(name);
                hasname = 1;
            }
        }
-       if(!glyph2unicode[t] && !hasname && skip_unused) {
-           continue;
-       }
-       error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
-       if(error) {
-           fprintf(stderr, "Couldn't load glyph %d, error:%d\n", t, error);
-           continue;
-       }
-       error = FT_Get_Glyph(face->glyph, &glyph);
-       if(error) {
-           fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
-           continue;
+
+#if 0 // some cantonese pdfs fail to work if this is activated
+
+       if(has_had_errors && (isunicode && !glyph2unicode[t]) && !hasname && t>=256) {
+           /* some freetype versions crash or corrupt memory if we try to load
+              characters (without unicode index or name) above 256 for some fonts.
+              So skip those characters once the first error occured */
+           omit = 1;
        }
+#endif
+
+       if(!omit) {
+           error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
+           if(error) {
+               if(hasname)
+                   fprintf(stderr, "Warning: glyph %d/%d (unicode %d, name %s) has return code %d\n", t, (int)face->num_glyphs, glyph2unicode[t], name, error);
+               else
+                   fprintf(stderr, "Warning: glyph %d/%d (unicode %d) has return code %d\n", t, (int)face->num_glyphs, glyph2unicode[t], error);
+               omit = 2;
 
-       FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
-       bbox.yMin = -bbox.yMin;
-       bbox.yMax = -bbox.yMax;
-       if(bbox.xMax < bbox.xMin) {
-           // swap
-           bbox.xMax ^= bbox.xMin;
-           bbox.xMin ^= bbox.xMax;
-           bbox.xMax ^= bbox.xMin;
+#if 0
+               if(!has_had_errors) {
+                   char buf[256];
+                   if(fontname && *fontname) {
+                       fprintf(stderr, "font has been copied to %s.ttf\n", fontname);
+                       sprintf(buf, "cp %s %s.ttf", filename, fontname);
+                   } else {
+                       fprintf(stderr, "font has been copied to badfont%d.ttf\n", errorno);
+                       sprintf(buf, "cp %s badfont%d.ttf", filename, errorno);
+                       errorno++;
+                   }
+                   system(buf);
+               }
+#endif
+               has_had_errors = 1;
+           }
        }
-       if(bbox.yMax < bbox.yMin) {
-           // swap
-           bbox.yMax ^= bbox.yMin;
-           bbox.yMin ^= bbox.yMax;
-           bbox.yMax ^= bbox.yMin;
+       if(!omit) {
+           error = FT_Get_Glyph(face->glyph, &glyph);
+           if(error) {
+               fprintf(stderr, "Couldn't get glyph %d/%d, error:%d\n", t, (int)face->num_glyphs, error);
+               omit = 3;
+           }
        }
 
-       gfxdrawer_target_gfxline(&draw);
-       info.draw = &draw;
-       info.quality = quality;
-
-       //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
-       error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
-       
-       if(error) {
-           fprintf(stderr, "Couldn't decompose glyph %d\n", t);
-           gfxline_free((gfxline_t*)draw.result(&draw));
-           continue;
+       if(!omit) {
+           gfxline_t*l;
+           int ok=0;
+           gfxdrawer_target_gfxline(&draw);
+           info.draw = &draw;
+           info.quality = quality;
+
+           //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
+           error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
+           
+           if(error) {
+               fprintf(stderr, "Couldn't decompose glyph %d\n", t);
+               gfxline_free((gfxline_t*)draw.result(&draw));
+               FT_Done_Glyph(glyph);
+               omit = 4;
+           } else {
+               font->glyphs[font->num_glyphs].advance = glyph->advance.x/65536;
+               font->glyphs[font->num_glyphs].line = (gfxline_t*)draw.result(&draw);
+           }
+           l = font->glyphs[font->num_glyphs].line;
+           while(l) {
+               if(l->type != gfx_moveTo) {
+                   ok = 1;
+               }
+               l = l->next;
+           }
+           if(!ok && !name) {
+               gfxline_free(font->glyphs[font->num_glyphs].line);
+               font->glyphs[font->num_glyphs].line = 0;
+               font->glyphs[font->num_glyphs].advance = 0;
+
+               /* Some PDFs created e.g. by InDesign tend to create
+                  fonts with reduced (empty) characters, which still
+                  have unicode indices attached to them.
+                  Remove that information, in order to not confuse
+                  any converter applications.
+                   */
+               font->glyphs[font->num_glyphs].unicode = 0;
+               if(font->glyphs[font->num_glyphs].name) {
+                   free((void*)font->glyphs[font->num_glyphs].name);
+                   font->glyphs[font->num_glyphs].name = 0;
+               }
+               FT_Done_Glyph(glyph);
+               omit = 5;
+           }
        }
 
-#if 0
-       if(bbox.xMin > 0) {
-           font->glyph[font->num_glyphs].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
-       } else {
-           font->glyph[font->num_glyphs].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
+       if(!omit) {
+           FT_Done_Glyph(glyph);
+           font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
        }
-#else
-       font->glyphs[font->num_glyphs].advance = glyph->advance.x*20/65536;
-#endif
-       
-       font->glyphs[font->num_glyphs].line = (gfxline_t*)draw.result(&draw);
-       
-       /*font->glyphs[font->num_glyphs].bbox.xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
-       font->glyphs[font->num_glyphs].bbox.ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
-       font->glyphs[font->num_glyphs].bbox.xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
-       font->glyphs[font->num_glyphs].bbox.ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;*/
 
-       FT_Done_Glyph(glyph);
-       font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
        glyph2glyph[t] = font->num_glyphs;
        font->num_glyphs++;
     }
+
     /* notice: if skip_unused is true, font->glyph2unicode, font->glyphnames and font->layout->bounds will 
               have more memory allocated than just font->num_glyphs, but only the first font->numchars 
               are used/valid */
@@ -354,13 +433,13 @@ gfxfont_t* gfxfont_load(char*filename, double quality)
 
     FT_Done_Face(face);
     FT_Done_FreeType(ftlibrary);ftlibrary=0;
-  
-    if(!isunicode && font->num_glyphs>0) {
+    if(!isunicode && font->num_glyphs>0 && font->max_unicode) {
        /* if the encoding isn't unicode, remap the font
           so that the encoding equals the char position, and
           remove the unicode table */
        int t;
-       gfxglyph_t*newglyphs = rfx_calloc(font->max_unicode*sizeof(gfxglyph_t));
+       gfxglyph_t*newglyphs = (gfxglyph_t*)rfx_calloc(font->max_unicode*sizeof(gfxglyph_t));
 
        for(t=0;t<max_unicode;t++) {
            int c = font->unicode2glyph[t];
@@ -409,10 +488,33 @@ gfxfont_t* gfxfont_load(char*filename, double quality)
 }
 #else
 
-gfxfont_t* gfxfont_load(char*filename)
+gfxfont_t* gfxfont_load(char*id, char*filename, unsigned int flags, double quality)
 {
     fprintf(stderr, "No freetype support compiled in! Not able to load %s\n", filename);
 }
 
 #endif
 
+void gfxfont_free(gfxfont_t*font)
+{
+    int t;
+    for(t=0;t<font->num_glyphs;t++) {
+       glyph_clear(&font->glyphs[t]);
+    }
+    if(font->glyphs) {
+       free(font->glyphs);font->glyphs = 0;
+    }
+    font->num_glyphs = 0;
+    if(font->unicode2glyph) {
+       free(font->unicode2glyph);font->unicode2glyph = 0;
+    }
+    if(font->id) {
+       free((void*)font->id);font->id=0;
+    }
+    if(font->kerning) {
+       free(font->kerning);font->kerning=0;
+    }
+
+    free(font);
+}
+