fixed z-order problems in poly2bitmap
[swftools.git] / lib / ttf.c
index f389ff9..5aa6e10 100644 (file)
--- a/lib/ttf.c
+++ b/lib/ttf.c
@@ -24,6 +24,7 @@
 #include <memory.h>
 #include "log.h"
 #include "os.h"
+#include "q.h"
 #include "mem.h"
 #include "ttf.h"
 
@@ -597,8 +598,9 @@ static table_maxp_t*maxp_new(ttf_t*ttf)
 {
     table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
     int t;
+    maxp->maxContours=1;
     if(ttf->num_glyphs) {
-       int max = 0;
+       int max = 1;
        for(t=0;t<ttf->num_glyphs;t++) {
            if(ttf->glyphs[t].num_points>max)
                max = ttf->glyphs[t].num_points;
@@ -1219,6 +1221,7 @@ void cmap_parse(memreader_t*r, ttf_t*ttf)
     readU16(r); // version (0)
     int num_subtables = readU16(r);
     int t;
+    char warn=1;
     if(r->pos+num_subtables*8 > r->size) {
        msg("<warning> CMap overflow");
        num_subtables = (r->size-r->pos)/8;
@@ -1276,6 +1279,7 @@ void cmap_parse(memreader_t*r, ttf_t*ttf)
            INIT_READ(r_delta, t.mem, t.size, t.pos+2+segment_count*4);
            INIT_READ(r_range, t.mem, t.size, t.pos+2+segment_count*6);
            int glyphmap_start = t.pos+2+segment_count*8;
+           int glyphmap_size = t.size - glyphmap_start;
            int s;
            for(s=0;s<segment_count;s++) {
                U16 start = readU16(&r_start);
@@ -1298,7 +1302,12 @@ void cmap_parse(memreader_t*r, ttf_t*ttf)
                        ttf->unicode[u] = (u + delta) & 0xffff;
                    }
                } else {
-                   INIT_READ(g, t.mem, t.size, r_range.pos-2+range);
+                   int pos = r_range.pos-2+range;
+                   if(warn && pos+end-start+1 > t.size) {
+                       msg("<warning> glyphmap index out of bounds (%d-%d/%d)", pos, pos+end-start, t.size);
+                       warn=0;
+                   }
+                   INIT_READ(g, t.mem, t.size, pos);
                    for(u=start;u<=end;u++) {
                        ttf->unicode[u] = readU16(&g);
                    }
@@ -1363,6 +1372,8 @@ void cmap_write(ttf_t* ttf, ttf_table_t*w)
 
     num_segments++; // account for 0xffff mapping
 
+    int glyphmap_start = w->len+2+num_segments*8;
+    
     int t;
     int end_pos = w->len;
     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
@@ -1373,10 +1384,10 @@ void cmap_write(ttf_t* ttf, ttf_table_t*w)
     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //delta array
     int range_pos = w->len;
     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //range array
-    
+           
     w->data[num_segments_pos]=(num_segments*2)>>8;
     w->data[num_segments_pos+1]=(num_segments*2);
-
+    
     pos=0;
     num_segments = 0;
     while(pos < ttf->unicode_size) {
@@ -1393,7 +1404,7 @@ void cmap_write(ttf_t* ttf, ttf_table_t*w)
        U16 delta = ttf->unicode[pos]-pos;
        char do_delta=1;
        for(s=pos+1;s<=end;s++) {
-           U16 delta2 = ttf->unicode[pos]-pos;
+           U16 delta2 = ttf->unicode[s]-s;
            if(delta2!=delta) {
                do_delta=0;
                break;
@@ -1404,7 +1415,7 @@ void cmap_write(ttf_t* ttf, ttf_table_t*w)
            range = 0;
        } else {
            delta = 0;
-           range = w->len - range_pos+num_segments*2;
+           range = w->len - range_pos;
            for(s=pos;s<=end;s++) {
                writeU16(w, ttf->unicode[s]);
            }
@@ -1453,12 +1464,11 @@ void name_parse(memreader_t*r, ttf_t*ttf)
        U16 name_id = readU16(r);
        U16 len = readU16(r);
        U16 offset_2 = readU16(r);
-       /*printf("%d %d %d %d at %d, %d bytes:", platform, encoding, language, name_id, offset+offset_2, len);
-       int s;
-       for(s=0;s<len;s++) {
-           printf("%c", r->mem[offset+offset_2+s]);
+       if(name_id==4) {
+           if(ttf->name)
+               free(ttf->name);
+           ttf->name = strdup_n(&r->mem[offset+offset_2], len);
        }
-       printf("\n");*/
     }
 }
 void name_write(ttf_t*ttf, ttf_table_t*table)
@@ -1482,8 +1492,49 @@ void name_write(ttf_t*ttf, ttf_table_t*table)
 }
 void name_delete(ttf_t*ttf)
 {
-    if(ttf->name)
+    if(ttf->name) {
        free(ttf->name);
+       ttf->name=0;
+    }
+}
+
+static table_post_t*post_new(ttf_t*ttf)
+{
+    table_post_t*post = rfx_calloc(sizeof(table_post_t));
+    return post;
+}
+void post_parse(memreader_t*r, ttf_t*ttf)
+{
+    table_post_t*post = ttf->post = rfx_calloc(sizeof(table_post_t));
+    U16 format = readU16(r);
+    post->italic_angle = readU16(r);
+    post->underline_position = readU16(r);
+    post->underline_thickness = readU16(r);
+    U16 is_monospaced = readU16(r);
+    readU16(r); // min mem 42
+    readU16(r);
+    readU16(r); // min mem 1
+    readU16(r);
+}
+void post_write(ttf_t*ttf, ttf_table_t*table)
+{
+    table_post_t*post = ttf->post;
+    writeU32(table, 0x00030000);
+    writeU32(table, post->italic_angle);
+    writeU16(table, post->underline_position);
+    writeU16(table, post->underline_thickness);
+    writeU32(table, 0); //is monospaced TODO
+    writeU32(table, 0); //min mem 42
+    writeU32(table, 0);
+    writeU32(table, 0); //min mem 1
+    writeU32(table, 0);
+}
+void post_delete(ttf_t*ttf)
+{
+    if(ttf->post) {
+       free(ttf->post);
+       ttf->post = 0;
+    }
 }
 
 static int ttf_parse_tables(ttf_t*ttf)
@@ -1579,6 +1630,13 @@ static int ttf_parse_tables(ttf_t*ttf)
        ttf_table_delete(ttf, table);
     }
 
+    table = ttf_find_table(ttf, TAG_POST);
+    if(table) {
+       INIT_READ(m, table->data, table->len, 0);
+       post_parse(&m, ttf);
+       ttf_table_delete(ttf, table);
+    }
+
     return 1;
 }
 static void ttf_collapse_tables(ttf_t*ttf)
@@ -1625,6 +1683,11 @@ static void ttf_collapse_tables(ttf_t*ttf)
        name_write(ttf, table);
        name_delete(ttf);
     }
+    if(ttf->post) {
+       table = ttf_addtable(ttf, TAG_POST);
+       post_write(ttf, table);
+       post_delete(ttf);
+    }
     
     table = ttf_addtable(ttf, TAG_HEAD);
     head_write(ttf, table, loca_size);
@@ -1731,6 +1794,8 @@ void ttf_create_truetype_tables(ttf_t*ttf)
        ttf->hea = hea_new(ttf);
     if(!ttf->os2)
        ttf->os2 = os2_new(ttf);
+    if(!ttf->post)
+       ttf->post = post_new(ttf);
 }
 ttf_table_t* ttf_write(ttf_t*ttf)
 {
@@ -1831,7 +1896,7 @@ void ttf_dump(ttf_t*ttf)
     maxp_dump(ttf);
     glyf_dump(ttf);
 }
-void ttf_destroy(ttf_t*ttf)
+void ttf_destroy_tables(ttf_t*ttf)
 {
     ttf_table_t*table = ttf->tables;
     while(table) {
@@ -1840,11 +1905,22 @@ void ttf_destroy(ttf_t*ttf)
        free(table);
        table = next;
     }
+    ttf->tables = 0;
+}
+void ttf_reduce(ttf_t*ttf)
+{
+    ttf_destroy_tables(ttf);
+}
+void ttf_destroy(ttf_t*ttf)
+{
+    ttf_destroy_tables(ttf);
     maxp_delete(ttf);
     os2_delete(ttf);
     head_delete(ttf);
     hea_delete(ttf);
     glyf_delete(ttf);
+    post_delete(ttf);
+    name_delete(ttf);
     free(ttf);
 }
 
@@ -1858,13 +1934,18 @@ int main(int argn, const char*argv[])
     //msg("<notice> Loading %s", filename);
     memfile_t*m = memfile_open(filename);
     ttf_t*ttf = ttf_load(m->data, m->len);
+    if(!ttf) {
+       msg("<error> Couldn't load %s", filename);
+       return 1;
+    }
+    ttf_reduce(ttf);
     ttf->name = strdup("testfont");
     if(!ttf) return 1;
     memfile_close(m);
     //ttf_dump(ttf);
     //printf("os2 version: %04x (%d), maxp size: %d\n", 
 //         ttf->os2->version, ttf->os2->size, ttf->maxp->size);
-    ttf_save(ttf, "output.ttf");
+    ttf_save(ttf, "testfont.ttf");
     ttf_destroy(ttf);
     return 0;