fixed bug in unicode relocation
[swftools.git] / lib / gfxfont.c
index cc6c62c..760db9a 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 <assert.h>
 #include "../config.h"
 #include "gfxdevice.h"
 #include "gfxtools.h"
 #include "gfxfont.h"
 #include "ttf.h"
+#include "mem.h"
+#include "log.h"
 
 static int loadfont_scale = 64;
 static int full_unicode = 1;
@@ -520,6 +523,76 @@ void gfxfont_free(gfxfont_t*font)
     free(font);
 }
 
+static inline int invalid_unicode(int u)
+{
+    return (u<32 || (u>=0xe000 && u<0xf900));
+}
+void gfxfont_fix_unicode(gfxfont_t*font)
+{
+    int t;
+
+    /* find the current maximum unicode2glyph */
+    int max = 0;
+    for(t=0;t<font->num_glyphs;t++) {
+       int u = font->glyphs[t].unicode;
+       if(u > max)
+           max = u;
+    }
+    char*used = rfx_calloc(max+1);
+
+    /* now, remap all duplicates (and invalid characters) and
+       calculate the new maximum */
+    int remap_pos=0;
+    max = 0;
+    for(t=0;t<font->num_glyphs;t++) {
+       int u = font->glyphs[t].unicode;
+       if(u>=0) {
+           if(used[u] || invalid_unicode(u)) {
+               u = font->glyphs[t].unicode = 0xe000 + remap_pos++;
+           } else {
+               used[u] = 1;
+           }
+       }
+       if(u > max)
+           max = u;
+    }
+    free(used);
+    
+    if(!font->unicode2glyph) {
+       /* (re)generate unicode2glyph-to-glyph mapping table by reverse mapping
+          the glyph unicode2glyph's indexes into the mapping table. For collisions,
+          we prefer the smaller unicode2glyph value.*/
+       font->max_unicode = max+1;
+       font->unicode2glyph = malloc(sizeof(font->unicode2glyph[0])*(font->max_unicode));
+       memset(font->unicode2glyph, -1, sizeof(font->unicode2glyph[0])*(font->max_unicode));
+       
+       for(t=0;t<font->num_glyphs;t++) {
+           int u = font->glyphs[t].unicode;
+           if(u>=0) {
+               assert(font->unicode2glyph[u]<0); // we took care of duplicates, right?
+               assert(u<font->max_unicode);
+               font->unicode2glyph[u] = t;
+           }
+       }
+    } else {
+       /* add the new glyph indexes (most probably, that's only the remapped values
+          at 0xe000) to the unicode2glyph table. Notice: Unlike glyph2unicode, we don't
+          care about collisions in the unicode2glyph table */
+       int new_max_unicode = max+1;
+       if(font->max_unicode < new_max_unicode) {
+           font->unicode2glyph = rfx_realloc(font->unicode2glyph, sizeof(font->unicode2glyph[0])*(font->max_unicode));
+           memset(font->unicode2glyph+font->max_unicode, -1, sizeof(font->unicode2glyph[0])*(new_max_unicode - font->max_unicode));
+       }
+       for(t=0;t<font->num_glyphs;t++) {
+           int u = font->glyphs[t].unicode;
+           if(u>=0 && font->unicode2glyph[u]<0) {
+               font->unicode2glyph[u] = t;
+           }
+       }
+       font->max_unicode = new_max_unicode;
+    }
+}
+
 ttf_t* gfxfont_to_ttf(gfxfont_t*font)
 {
     ttf_t*ttf = ttf_new();
@@ -539,6 +612,7 @@ ttf_t* gfxfont_to_ttf(gfxfont_t*font)
     ttf->glyphs = rfx_calloc(num_glyphs*sizeof(ttfglyph_t));
     double scale = 1.0;
     int max_unicode = font->max_unicode;
+    int remap_pos=0;
     for(t=0;t<font->num_glyphs;t++) {
        gfxglyph_t*src = &font->glyphs[t];
        ttfglyph_t*dest = &ttf->glyphs[t+offset];
@@ -553,6 +627,7 @@ ttf_t* gfxfont_to_ttf(gfxfont_t*font)
        dest->num_points = count;
        dest->points = rfx_calloc(count*sizeof(ttfpoint_t));
        count = 0;
+       line = src->line;
        while(line) {
            if(line->type == gfx_splineTo) {
                dest->points[count].x = line->sx*scale;
@@ -570,6 +645,8 @@ ttf_t* gfxfont_to_ttf(gfxfont_t*font)
            count++;
            line=line->next;
        }
+       if(count)
+           dest->points[count-1].flags |= GLYPH_CONTOUR_END;
 
        /* compute bounding box */
        int s;
@@ -578,38 +655,65 @@ ttf_t* gfxfont_to_ttf(gfxfont_t*font)
            dest->ymin = dest->ymax = dest->points[0].y;
            for(s=1;s<count;s++) {
                if(dest->points[s].x < dest->xmin) 
-                   dest->xmin = dest->points[0].x;
-               if(dest->points[s].y < dest->xmin) 
-                   dest->xmin = dest->points[0].y;
-               if(dest->points[s].x > dest->xmin) 
-                   dest->xmax = dest->points[0].x;
-               if(dest->points[s].y > dest->xmin) 
-                   dest->ymax = dest->points[0].y;
+                   dest->xmin = dest->points[s].x;
+               if(dest->points[s].y < dest->ymin) 
+                   dest->ymin = dest->points[s].y;
+               if(dest->points[s].x > dest->xmax) 
+                   dest->xmax = dest->points[s].x;
+               if(dest->points[s].y > dest->ymax) 
+                   dest->ymax = dest->points[s].y;
            }
        }
 
        dest->advance = src->advance*scale;
-       if(src->unicode > max_unicode)
-           max_unicode = src->unicode;
+
+       int u = font->glyphs[t].unicode;
+       if(u > max_unicode)
+           max_unicode = u;
     }
     ttf->unicode_size = max_unicode+1;
     ttf->unicode = rfx_calloc(sizeof(unicode_t)*ttf->unicode_size);
-    for(t=0;t<ttf->num_glyphs;t++) {
-       gfxglyph_t*src = &font->glyphs[t];
-       int u = font->glyphs[t].unicode;
-       if(u>=0)
-           ttf->unicode[u] = t+offset;
-    }
-    int u;
-    for(u=0;u<font->max_unicode;u++) {
-       int g = font->unicode2glyph[t];
-       if(g>=0) {
-           ttf->unicode[u] = g;
+    
+    if(!font->unicode2glyph) {
+       for(t=0;t<font->num_glyphs;t++) {
+           gfxglyph_t*src = &font->glyphs[t];
+           int u = font->glyphs[t].unicode;
+           if(u<=0)
+               continue;
+           if(u<32) {
+               msg("<warning> gfxfont_to_ttf: glyph %d has an invalid unicode (%d)", t, u);
+               continue;
+           } else if(ttf->unicode[u]) {
+               msg("<warning> gfxfont_to_ttf: glyph %d has a duplicate unicode (%d)", t, u);
+               continue;
+           }
+           if(u<ttf->unicode_size)
+               ttf->unicode[u] = t+offset;
+       }
+    } else {
+       int u;
+       for(u=1;u<font->max_unicode;u++) {
+           int g = font->unicode2glyph[u];
+           if(g>=0 && u<32) {
+               msg("<warning> gfxfont_to_ttf: Font contains an invalid unicode (%d)", u);
+               continue;
+           }
+           if(g>=0 && g<font->num_glyphs && !ttf->unicode[u]) {
+               ttf->unicode[u] = g+offset;
+           }
        }
     }
+       
     ttf->ascent = font->ascent;
-    ttf->descent = font->descent;
-    ttf->lineGap = font->ascent + font->descent;
+    ttf->descent = -font->descent;
+    ttf->lineGap = 0;
+
+    ttf->full_name = strdup(font->id);
+    ttf->family_name = strdup(font->id);
+    ttf->subfamily_name = strdup(font->id);
+    ttf->postscript_name = strdup(font->id);
+    ttf->version_string = strdup("Version 1.0");
+    ttf->font_uid = strdup(font->id);
 
     ttf_create_truetype_tables(ttf);
     return ttf;
@@ -619,5 +723,13 @@ void gfxfont_save(gfxfont_t*font, const char*filename)
 {
     ttf_t*ttf = gfxfont_to_ttf(font);
     ttf_save(ttf, filename);
+    ttf_destroy(ttf);
+}
+
+void gfxfont_save_eot(gfxfont_t*font, const char*filename)
+{
+    ttf_t*ttf = gfxfont_to_ttf(font);
+    ttf_save_eot(ttf, filename);
+    ttf_destroy(ttf);
 }