added gfxfont_save() to gfxfont.{c,h}
authorMatthias Kramm <kramm@quiss.org>
Thu, 18 Feb 2010 04:00:58 +0000 (20:00 -0800)
committerMatthias Kramm <kramm@quiss.org>
Thu, 18 Feb 2010 04:00:58 +0000 (20:00 -0800)
lib/Makefile.in
lib/devices/swf.c
lib/gfxfont.c
lib/gfxfont.h
lib/ruby/test.rb
lib/ttf.c
lib/ttf.h

index d1c5375..857d928 100644 (file)
@@ -18,7 +18,7 @@ gfxpoly_objects = gfxpoly/active.$(O) gfxpoly/convert.$(O) gfxpoly/poly.$(O) gfx
 
 rfxswf_modules =  modules/swfbits.c modules/swfaction.c modules/swfdump.c modules/swfcgi.c modules/swfbutton.c modules/swftext.c modules/swffont.c modules/swftools.c modules/swfsound.c modules/swfshape.c modules/swfobject.c modules/swfdraw.c modules/swffilter.c modules/swfrender.c h.263/swfvideo.c modules/swfalignzones.c
 
 
 rfxswf_modules =  modules/swfbits.c modules/swfaction.c modules/swfdump.c modules/swfcgi.c modules/swfbutton.c modules/swftext.c modules/swffont.c modules/swftools.c modules/swfsound.c modules/swfshape.c modules/swfobject.c modules/swfdraw.c modules/swffilter.c modules/swfrender.c h.263/swfvideo.c modules/swfalignzones.c
 
-base_objects=q.$(O) utf8.$(O) png.$(O) jpeg.$(O) wav.$(O) mp3.$(O) os.$(O) bitio.$(O) log.$(O) mem.$(O) MD5.$(O) xml.$(O)
+base_objects=q.$(O) utf8.$(O) png.$(O) jpeg.$(O) wav.$(O) mp3.$(O) os.$(O) bitio.$(O) log.$(O) mem.$(O) MD5.$(O) xml.$(O) ttf.$(O)
 gfx_objects=gfximage.$(O) gfxtools.$(O) gfxfont.$(O) devices/dummy.$(O) devices/file.$(O) devices/render.$(O) devices/text.$(O) devices/record.$(O) devices/ops.$(O) devices/polyops.$(O) devices/bbox.$(O) devices/rescale.$(O) @DEVICE_OPENGL@ @DEVICE_PDF@
 
 rfxswf_objects=modules/swfaction.$(O) modules/swfbits.$(O) modules/swfbutton.$(O) modules/swfcgi.$(O) modules/swfdraw.$(O) modules/swfdump.$(O) modules/swffilter.$(O) modules/swffont.$(O) modules/swfobject.$(O) modules/swfrender.$(O) modules/swfshape.$(O) modules/swfsound.$(O) modules/swftext.$(O) modules/swftools.$(O) modules/swfalignzones.$(O)
 gfx_objects=gfximage.$(O) gfxtools.$(O) gfxfont.$(O) devices/dummy.$(O) devices/file.$(O) devices/render.$(O) devices/text.$(O) devices/record.$(O) devices/ops.$(O) devices/polyops.$(O) devices/bbox.$(O) devices/rescale.$(O) @DEVICE_OPENGL@ @DEVICE_PDF@
 
 rfxswf_objects=modules/swfaction.$(O) modules/swfbits.$(O) modules/swfbutton.$(O) modules/swfcgi.$(O) modules/swfdraw.$(O) modules/swfdump.$(O) modules/swffilter.$(O) modules/swffont.$(O) modules/swfobject.$(O) modules/swfrender.$(O) modules/swfshape.$(O) modules/swfsound.$(O) modules/swftext.$(O) modules/swftools.$(O) modules/swfalignzones.$(O)
@@ -55,6 +55,8 @@ wav.$(O): wav.c wav.h $(top_builddir)/config.h
        $(C) wav.c -o $@
 xml.$(O): xml.c xml.h bitio.h
        $(C) xml.c -o $@
        $(C) wav.c -o $@
 xml.$(O): xml.c xml.h bitio.h
        $(C) xml.c -o $@
+ttf.$(O): ttf.c ttf.h
+       $(C) ttf.c -o $@
 os.$(O): os.c os.h $(top_builddir)/config.h
        $(C) -DSWFTOOLS_DATADIR=\"$(pkgdatadir)\" os.c -o $@
 modules/swfaction.$(O): modules/swfaction.c rfxswf.h
 os.$(O): os.c os.h $(top_builddir)/config.h
        $(C) -DSWFTOOLS_DATADIR=\"$(pkgdatadir)\" os.c -o $@
 modules/swfaction.$(O): modules/swfaction.c rfxswf.h
index af5d284..3a9cbd4 100644 (file)
@@ -2121,6 +2121,8 @@ int swf_setparameter(gfxdevice_t*dev, const char*name, const char*value)
        i->config_dumpfonts = atoi(value);
     } else if(!strcmp(name, "animate")) {
        i->config_animate = atoi(value);
        i->config_dumpfonts = atoi(value);
     } else if(!strcmp(name, "animate")) {
        i->config_animate = atoi(value);
+    } else if(!strcmp(name, "linknameurl")) {
+       i->config_linknameurl = atoi(value);
     } else if(!strcmp(name, "showimages")) {
        i->config_showimages = atoi(value);
     } else if(!strcmp(name, "disablelinks")) {
     } else if(!strcmp(name, "showimages")) {
        i->config_showimages = atoi(value);
     } else if(!strcmp(name, "disablelinks")) {
index efe29c3..cc6c62c 100644 (file)
@@ -25,6 +25,7 @@
 #include "gfxdevice.h"
 #include "gfxtools.h"
 #include "gfxfont.h"
 #include "gfxdevice.h"
 #include "gfxtools.h"
 #include "gfxfont.h"
+#include "ttf.h"
 
 static int loadfont_scale = 64;
 static int full_unicode = 1;
 
 static int loadfont_scale = 64;
 static int full_unicode = 1;
@@ -491,6 +492,7 @@ gfxfont_t* gfxfont_load(char*id, char*filename, unsigned int flags, double quali
 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);
 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);
+    return 0;
 }
 
 #endif
 }
 
 #endif
@@ -518,3 +520,104 @@ void gfxfont_free(gfxfont_t*font)
     free(font);
 }
 
     free(font);
 }
 
+ttf_t* gfxfont_to_ttf(gfxfont_t*font)
+{
+    ttf_t*ttf = ttf_new();
+    int num_glyphs = font->num_glyphs;
+    int offset = 0;
+    int t;
+    char has_nondef_glyph = 
+       font->num_glyphs && font->glyphs[0].unicode==-1 && 
+       (!font->glyphs[0].line || !font->glyphs[0].line->next);
+
+    if(!has_nondef_glyph) {
+       /* insert a new .nondef glyph at the start of the font */
+       offset++;
+       num_glyphs++;
+    }
+    ttf->num_glyphs = num_glyphs;
+    ttf->glyphs = rfx_calloc(num_glyphs*sizeof(ttfglyph_t));
+    double scale = 1.0;
+    int max_unicode = font->max_unicode;
+    for(t=0;t<font->num_glyphs;t++) {
+       gfxglyph_t*src = &font->glyphs[t];
+       ttfglyph_t*dest = &ttf->glyphs[t+offset];
+       gfxline_t*line = src->line;
+       int count = 0;
+       while(line) {
+           count++;
+           if(line->type == gfx_splineTo) 
+               count++;
+           line=line->next;
+       }
+       dest->num_points = count;
+       dest->points = rfx_calloc(count*sizeof(ttfpoint_t));
+       count = 0;
+       while(line) {
+           if(line->type == gfx_splineTo) {
+               dest->points[count].x = line->sx*scale;
+               dest->points[count].y = line->sy*scale;
+               count++;
+           }
+           dest->points[count].x = line->x*scale;
+           dest->points[count].y = line->y*scale;
+           dest->points[count].flags |= GLYPH_ON_CURVE;
+           if(line->type == gfx_moveTo) {
+               dest->points[count].flags |= GLYPH_CONTOUR_START;
+               if(count)
+                   dest->points[count-1].flags |= GLYPH_CONTOUR_END;
+           }
+           count++;
+           line=line->next;
+       }
+
+       /* compute bounding box */
+       int s;
+       if(count) {
+           dest->xmin = dest->xmax = dest->points[0].x;
+           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->advance = src->advance*scale;
+       if(src->unicode > max_unicode)
+           max_unicode = src->unicode;
+    }
+    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;
+       }
+    }
+    ttf->ascent = font->ascent;
+    ttf->descent = font->descent;
+    ttf->lineGap = font->ascent + font->descent;
+
+    ttf_create_truetype_tables(ttf);
+    return ttf;
+}
+
+void gfxfont_save(gfxfont_t*font, const char*filename)
+{
+    ttf_t*ttf = gfxfont_to_ttf(font);
+    ttf_save(ttf, filename);
+}
+
index 695e965..1058db6 100644 (file)
@@ -33,6 +33,7 @@ extern "C" {
 /* The quality parameter is given by 1 divided by the zoom factor at which the font
    still looks good. 1=normal, 0.5=double resolution etc. */
 gfxfont_t* gfxfont_load(char*id, char*filename, unsigned int flags, double quality);
 /* The quality parameter is given by 1 divided by the zoom factor at which the font
    still looks good. 1=normal, 0.5=double resolution etc. */
 gfxfont_t* gfxfont_load(char*id, char*filename, unsigned int flags, double quality);
+void gfxfont_save(gfxfont_t*font, const char*filename);
 void gfxfont_free(gfxfont_t*font);
 
 #ifdef __cplusplus
 void gfxfont_free(gfxfont_t*font);
 
 #ifdef __cplusplus
index 1c0418e..dc96d1b 100644 (file)
@@ -1,6 +1,6 @@
 require 'gfx'
 
 require 'gfx'
 
-pdf = GFX::PDF.new('file.pdf')
+pdf = GFX::PDF.new('segfault.pdf')
 
 class TestRender < GFX::Device
     def startpage(width,height)
 
 class TestRender < GFX::Device
     def startpage(width,height)
index c637f6e..c17b631 100644 (file)
--- a/lib/ttf.c
+++ b/lib/ttf.c
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <memory.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <memory.h>
-#include "bitio.h"
 #include "log.h"
 #include "os.h"
 #include "mem.h"
 #include "log.h"
 #include "os.h"
 #include "mem.h"
@@ -126,13 +125,13 @@ static void expand(ttf_table_t*w, int newsize)
     w->memsize = v1>v2?v1:v2;
     w->data = rfx_realloc(w->data, w->memsize);
 }
     w->memsize = v1>v2?v1:v2;
     w->data = rfx_realloc(w->data, w->memsize);
 }
-static void writeU8(ttf_table_t*w, unsigned char b)
+static inline void writeU8(ttf_table_t*w, unsigned char b)
 {
     if(w->memsize<w->len+1)
        expand(w, w->len+1);
     w->data[w->len++] = b;
 }
 {
     if(w->memsize<w->len+1)
        expand(w, w->len+1);
     w->data[w->len++] = b;
 }
-static void writeU16(ttf_table_t*w, unsigned short v)
+static inline void writeU16(ttf_table_t*w, unsigned short v)
 {
     if(w->memsize<w->len+2)
        expand(w, w->len+2);
 {
     if(w->memsize<w->len+2)
        expand(w, w->len+2);
@@ -140,7 +139,7 @@ static void writeU16(ttf_table_t*w, unsigned short v)
     w->data[w->len++] = v;
 }
 #define writeS16 writeU16
     w->data[w->len++] = v;
 }
 #define writeS16 writeU16
-static void writeU32(ttf_table_t*w, unsigned long v)
+static inline void writeU32(ttf_table_t*w, unsigned long v)
 {
     if(w->memsize<w->len+4)
        expand(w, w->len+4);
 {
     if(w->memsize<w->len+4)
        expand(w, w->len+4);
@@ -149,7 +148,7 @@ static void writeU32(ttf_table_t*w, unsigned long v)
     w->data[w->len++] = v>>8;
     w->data[w->len++] = v;
 }
     w->data[w->len++] = v>>8;
     w->data[w->len++] = v;
 }
-static void writeBlock(ttf_table_t*w, void*data, int len)
+static inline void writeBlock(ttf_table_t*w, void*data, int len)
 {
     if(w->memsize<w->len+len)
        expand(w, w->len+len);
 {
     if(w->memsize<w->len+len)
        expand(w, w->len+len);
@@ -258,16 +257,182 @@ static void ttf_table_dump(ttf_table_t*t, const char*prefix)
     hexdump(t->data, t->len, prefix);
 }
 
     hexdump(t->data, t->len, prefix);
 }
 
+static table_head_t*head_new(ttf_t*ttf)
+{
+    table_head_t*head = rfx_calloc(sizeof(table_head_t));
+    head->units_per_em = 1024;
+    int t;
+    if(ttf->num_glyphs) {
+       head->xmin = ttf->glyphs[0].xmin;
+       head->ymin = ttf->glyphs[0].ymin;
+       head->xmax = ttf->glyphs[0].xmax;
+       head->ymax = ttf->glyphs[0].ymax;
+       for(t=1;t<ttf->num_glyphs;t++) {
+           if(ttf->glyphs[0].xmin < head->xmin) head->xmin = ttf->glyphs[0].xmin;
+           if(ttf->glyphs[0].ymin < head->ymin) head->ymin = ttf->glyphs[0].ymin;
+           if(ttf->glyphs[0].xmax > head->xmax) head->xmax = ttf->glyphs[0].xmax;
+           if(ttf->glyphs[0].ymax > head->ymax) head->ymax = ttf->glyphs[0].ymax;
+       }
+    }
+    head->macStyle = 0;
+    head->lowest_readable_size = 8; // not sure what font renderers actually do with this
+    head->dir_hint = 0;
+    return head;
+}
+static int head_parse(ttf_t*ttf, memreader_t*r)
+{
+    ttf->head = rfx_calloc(sizeof(table_head_t));
+    U32 version = readU32(r);
+    if(version!=VERSION_1_0) 
+       msg("<warning> Font HEAD has unknown version %08x", version);
+    U32 revision = readU32(r);
+    U32 checksum2 = readU32(r);
+    U32 magic = readU32(r);
+    if(magic!=0x5f0f3cf5) 
+       msg("<warning> Font HEAD has unknown magic number %08x", magic);
+    ttf->head->flags = readU16(r);
+    ttf->head->units_per_em = readU16(r);
+    readU32(r);readU32(r); //created
+    readU32(r);readU32(r); //modified
+    ttf->head->xmin = readU16(r);
+    ttf->head->ymin = readU16(r);
+    ttf->head->xmax = readU16(r);
+    ttf->head->ymax = readU16(r);
+    ttf->head->macStyle = readU16(r);
+    ttf->head->lowest_readable_size = readU16(r); //in pixels
+    ttf->head->dir_hint = readS16(r);
+    int loc_index = readS16(r); //used in 'loca' table
+    if(loc_index>1)
+       msg("<warning> loca index format %d unknown", loc_index);
+    U16 glyph_data_format = readS16(r);
+    if(glyph_data_format!=0)
+       msg("<warning> Font glyph data format unknown: %04x", glyph_data_format);
+    if(r->pos < r->size) {
+       msg("<warning> Leftover bytes (%d) in HEAD tag", r->size - r->pos);
+    }
+    return loc_index;
+}
+static void head_write(ttf_t*ttf, ttf_table_t*w, int loca_size)
+{
+    writeU32(w, 0x10000);
+    writeU32(w, 0x10000);
+    writeU32(w, 0); //checksum
+    writeU32(w, 0x5f0f3cf5); //magic
+    writeU16(w, ttf->head->flags);
+    writeU16(w, ttf->head->units_per_em);
+    writeU32(w, 0);writeU32(w, 0); //created
+    writeU32(w, 0);writeU32(w, 0); //modified
+    writeU16(w, ttf->head->xmin);
+    writeU16(w, ttf->head->ymin);
+    writeU16(w, ttf->head->xmax);
+    writeU16(w, ttf->head->ymax);
+    writeU16(w, ttf->head->macStyle);
+    writeU16(w, ttf->head->lowest_readable_size);
+    writeS16(w, ttf->head->dir_hint);
+    writeS16(w, loca_size); //loca index size (32 bit)
+    writeS16(w, 0); //glyph data format
+}
+static void head_dump(ttf_t*ttf)
+{
+    printf("head->flags: %d\n", ttf->head->flags);
+    printf("head->units_per_em: %d\n", ttf->head->units_per_em);
+    printf("head->xmin: %d\n", ttf->head->xmin);
+    printf("head->ymin: %d\n", ttf->head->ymin);
+    printf("head->xmax: %d\n", ttf->head->xmax);
+    printf("head->ymax: %d\n", ttf->head->ymax);
+    printf("head->macStyle: %d\n", ttf->head->macStyle);
+    printf("head->lowest_readable_size: %d\n", ttf->head->lowest_readable_size);
+    printf("head->dir_hint: %d\n", ttf->head->dir_hint);
+}
+static void head_delete(ttf_t*ttf)
+{
+    if(ttf->head) {
+       free(ttf->head);
+       ttf->head=0;
+    }
+}
+
+static table_os2_t*os2_new(ttf_t*ttf)
+{
+    table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
+    if(ttf->num_glyphs) {
+       int average_width=0;
+       int t;
+       for(t=0;t<ttf->num_glyphs;t++) {
+           average_width += (ttf->glyphs[t].advance + ttf->glyphs[t].bearing);
+       }
+       os2->xAvgCharWidth = average_width / ttf->num_glyphs;
+    }
+
+    /* that's what everybody seems to fill in */
+    os2->usWeightClass = 400;
+    os2->usWidthClass = 5;
+   
+    if(ttf->head) {
+       int advance = (ttf->head->xmax - ttf->head->xmin)/2;
+       int height = (ttf->head->xmax - ttf->head->xmin);
+       int ymid = height/2;
+       /* I do believe a sane font rendering engine will actually use
+          the font advance here- the subscript/superscript position will
+          not be the same for each glyph */
+       os2->ySuperscriptXSize = os2->ySubscriptXSize = (ttf->head->xmax - ttf->head->xmin)/2;
+       os2->ySuperscriptYSize = os2->ySubscriptYSize = (ttf->head->ymax - ttf->head->ymin)/2;
+       os2->ySubscriptXOffset = advance;
+       os2->ySubscriptYOffset = 0;
+       os2->ySuperscriptXOffset = advance;
+       os2->ySuperscriptYOffset = (ttf->head->ymax - ttf->head->ymin)/2;
+       os2->yStrikeoutSize = ttf->head->units_per_em / 10;
+       os2->yStrikeoutPosition = ymid;
+       os2->usWinAscent = ttf->head->ymax;
+       os2->usWinDescent = ttf->head->ymin<0?0:ttf->head->ymin;
+       os2->sxHeight = ymid;
+       os2->sCapHeight = height*2/3;
+    }
+    os2->panose_Weight = 4;
+
+    /* strictly speaking we'd have to set 92/64 bits in these tables, depending on
+       what parts of the unicode table is filled. (e.g. bit 90 = tibetan). */
+    os2->ulCharRange[0] = 1;
+    os2->ulCharRange[1] = 0;
+    os2->ulCharRange[2] = 0;
+    os2->ulCharRange[3] = 0;
+    os2->ulCodePageRange1 = 1;
+    os2->ulCodePageRange2 = 0;
+
+    if(ttf->unicode_size) {
+       int min,max;
+       for(min=0;min<ttf->unicode_size;min++)
+           if(ttf->unicode[min]) break;
+       for(max=ttf->unicode_size-1;max>=0;max--)
+           if(ttf->unicode[max]) break;
+       if(min<=max) {
+           os2->fsFirstCharIndex = min;
+           os2->fsLastCharIndex = max;
+       }
+    }
+    os2->sTypoAscender = ttf->ascent;
+    os2->sTypoDescender = ttf->descent;
+    os2->sTypoLineGap = ttf->lineGap;
+
+    os2->usDefaultChar = 0;
+    os2->usBreakChar = (ttf->unicode_size>0x20 && ttf->unicode[0x20])?0x20:0;
+    os2->usMaxContext = 0; // we don't use ligatures yet
+    return os2;
+}
 static table_os2_t*os2_parse(memreader_t*r)
 {
     table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
     U16 version = readU16(r);
 static table_os2_t*os2_parse(memreader_t*r)
 {
     table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
     U16 version = readU16(r);
-    if(version!=0 && version!=1 && version!=2)
+    /* 0 = TrueType 1.5
+       1 = TrueType 1.66
+       2 = OpenType 1.2
+       3 = OpenType 1.4 */
+    if(version!=0 && version!=1 && version!=2 && version!=3)
        msg("<warning> Unknown OS2 version: %04x", version);
     os2->xAvgCharWidth = readS16(r);
     os2->usWeightClass = readU16(r);
     os2->usWidthClass = readU16(r);
        msg("<warning> Unknown OS2 version: %04x", version);
     os2->xAvgCharWidth = readS16(r);
     os2->usWeightClass = readU16(r);
     os2->usWidthClass = readU16(r);
-    os2->fsType = readU16(r);
+    readU16(r); //fstype
     os2->ySubscriptXSize = readU16(r);
     os2->ySubscriptYSize = readU16(r);
     os2->ySubscriptXOffset = readU16(r);
     os2->ySubscriptXSize = readU16(r);
     os2->ySubscriptYSize = readU16(r);
     os2->ySubscriptXOffset = readU16(r);
@@ -293,10 +458,7 @@ static table_os2_t*os2_parse(memreader_t*r)
     os2->ulCharRange[1] = readU32(r);
     os2->ulCharRange[2] = readU32(r);
     os2->ulCharRange[3] = readU32(r);
     os2->ulCharRange[1] = readU32(r);
     os2->ulCharRange[2] = readU32(r);
     os2->ulCharRange[3] = readU32(r);
-    os2->achVendID[0] = readU8(r);
-    os2->achVendID[1] = readU8(r);
-    os2->achVendID[2] = readU8(r);
-    os2->achVendID[3] = readU8(r);
+    readU32(r); //vendor
     os2->fsSelection = readU16(r);
     os2->fsFirstCharIndex = readU16(r);
     os2->fsLastCharIndex = readU16(r);
     os2->fsSelection = readU16(r);
     os2->fsFirstCharIndex = readU16(r);
     os2->fsLastCharIndex = readU16(r);
@@ -314,10 +476,13 @@ static table_os2_t*os2_parse(memreader_t*r)
     os2->usDefaultChar = readU16(r);
     os2->usBreakChar = readU16(r);
     os2->usMaxContext = readU16(r);
     os2->usDefaultChar = readU16(r);
     os2->usBreakChar = readU16(r);
     os2->usMaxContext = readU16(r);
+    
+    if(r->pos < r->size) {
+       msg("<warning> Leftover bytes (%d) in OS2 tag", r->size - r->pos);
+    }
     return os2;
 }
     return os2;
 }
-
-static os2_write(ttf_t*ttf, ttf_table_t*w)
+static void os2_write(ttf_t*ttf, ttf_table_t*w)
 {
     table_os2_t*os2 = ttf->os2;
     U16 version=1;
 {
     table_os2_t*os2 = ttf->os2;
     U16 version=1;
@@ -328,7 +493,7 @@ static os2_write(ttf_t*ttf, ttf_table_t*w)
     writeS16(w, os2->xAvgCharWidth);
     writeU16(w, os2->usWeightClass);
     writeU16(w, os2->usWidthClass);
     writeS16(w, os2->xAvgCharWidth);
     writeU16(w, os2->usWeightClass);
     writeU16(w, os2->usWidthClass);
-    writeU16(w, os2->fsType);
+    writeU16(w, 0); //fstype
     writeU16(w, os2->ySubscriptXSize);
     writeU16(w, os2->ySubscriptYSize);
     writeU16(w, os2->ySubscriptXOffset);
     writeU16(w, os2->ySubscriptXSize);
     writeU16(w, os2->ySubscriptYSize);
     writeU16(w, os2->ySubscriptXOffset);
@@ -354,10 +519,7 @@ static os2_write(ttf_t*ttf, ttf_table_t*w)
     writeU32(w, os2->ulCharRange[1]);
     writeU32(w, os2->ulCharRange[2]);
     writeU32(w, os2->ulCharRange[3]);
     writeU32(w, os2->ulCharRange[1]);
     writeU32(w, os2->ulCharRange[2]);
     writeU32(w, os2->ulCharRange[3]);
-    writeU8(w, os2->achVendID[0]);
-    writeU8(w, os2->achVendID[1]);
-    writeU8(w, os2->achVendID[2]);
-    writeU8(w, os2->achVendID[3]);
+    writeU32(w, 0x53434244); //vendor
     writeU16(w, os2->fsSelection);
     writeU16(w, os2->fsFirstCharIndex);
     writeU16(w, os2->fsLastCharIndex);
     writeU16(w, os2->fsSelection);
     writeU16(w, os2->fsFirstCharIndex);
     writeU16(w, os2->fsLastCharIndex);
@@ -376,21 +538,13 @@ static os2_write(ttf_t*ttf, ttf_table_t*w)
     writeU16(w, os2->usBreakChar);
     writeU16(w, os2->usMaxContext);
 }
     writeU16(w, os2->usBreakChar);
     writeU16(w, os2->usMaxContext);
 }
-static void os2_delete(ttf_t*ttf)
-{
-    if(ttf->os2)
-       free(ttf->os2);
-    ttf->os2=0;
-}
-
-static os2_dump(ttf_t*ttf)
+static void os2_dump(ttf_t*ttf)
 {
     table_os2_t*os2 = ttf->os2;
     if(!os2) return;
     printf("os2->xAvgCharWidth: %d\n", os2->xAvgCharWidth);
     printf("os2->usWeightClass: %d\n", os2->usWeightClass);
     printf("os2->usWidthClass: %d\n", os2->usWidthClass);
 {
     table_os2_t*os2 = ttf->os2;
     if(!os2) return;
     printf("os2->xAvgCharWidth: %d\n", os2->xAvgCharWidth);
     printf("os2->usWeightClass: %d\n", os2->usWeightClass);
     printf("os2->usWidthClass: %d\n", os2->usWidthClass);
-    printf("os2->fsType: %d\n", os2->fsType);
     printf("os2->ySubscriptXSize: %d\n", os2->ySubscriptXSize);
     printf("os2->ySubscriptYSize: %d\n", os2->ySubscriptYSize);
     printf("os2->ySubscriptXOffset: %d\n", os2->ySubscriptXOffset);
     printf("os2->ySubscriptXSize: %d\n", os2->ySubscriptXSize);
     printf("os2->ySubscriptYSize: %d\n", os2->ySubscriptYSize);
     printf("os2->ySubscriptXOffset: %d\n", os2->ySubscriptXOffset);
@@ -416,10 +570,6 @@ static os2_dump(ttf_t*ttf)
     printf("os2->ulCharRange[1]: %d\n", os2->ulCharRange[1]);
     printf("os2->ulCharRange[2]: %d\n", os2->ulCharRange[2]);
     printf("os2->ulCharRange[3]: %d\n", os2->ulCharRange[3]);
     printf("os2->ulCharRange[1]: %d\n", os2->ulCharRange[1]);
     printf("os2->ulCharRange[2]: %d\n", os2->ulCharRange[2]);
     printf("os2->ulCharRange[3]: %d\n", os2->ulCharRange[3]);
-    printf("os2->achVendID[0]: %d\n", os2->achVendID[0]);
-    printf("os2->achVendID[1]: %d\n", os2->achVendID[1]);
-    printf("os2->achVendID[2]: %d\n", os2->achVendID[2]);
-    printf("os2->achVendID[3]: %d\n", os2->achVendID[3]);
     printf("os2->fsSelection: %d\n", os2->fsSelection);
     printf("os2->fsFirstCharIndex: %d\n", os2->fsFirstCharIndex);
     printf("os2->fsLastCharIndex: %d\n", os2->fsLastCharIndex);
     printf("os2->fsSelection: %d\n", os2->fsSelection);
     printf("os2->fsFirstCharIndex: %d\n", os2->fsFirstCharIndex);
     printf("os2->fsLastCharIndex: %d\n", os2->fsLastCharIndex);
@@ -436,80 +586,39 @@ static os2_dump(ttf_t*ttf)
     printf("os2->usBreakChar: %d\n", os2->usBreakChar);
     printf("os2->usMaxContext: %d\n", os2->usMaxContext);
 }
     printf("os2->usBreakChar: %d\n", os2->usBreakChar);
     printf("os2->usMaxContext: %d\n", os2->usMaxContext);
 }
-
-static int head_parse(ttf_t*ttf, memreader_t*r)
+static void os2_delete(ttf_t*ttf)
 {
 {
-    ttf->head = rfx_calloc(sizeof(table_head_t));
-    U32 version = readU32(r);
-    if(version!=VERSION_1_0) 
-       msg("<warning> Font HEAD has unknown version %08x", version);
-    U32 revision = readU32(r);
-    if(revision!=VERSION_1_0) 
-       msg("<warning> Font HEAD has unknown revision %08x", revision);
-    U32 checksum2 = readU32(r);
-    U32 magic = readU32(r);
-    if(magic!=0x5f0f3cf5) 
-       msg("<warning> Font HEAD has unknown magic number %08x", magic);
-    ttf->head->flags = readU16(r);
-    ttf->head->units_per_em = readU16(r);
-    readU32(r);readU32(r); //created
-    readU32(r);readU32(r); //modified
-    ttf->head->xmin = readU16(r);
-    ttf->head->ymin = readU16(r);
-    ttf->head->xmax = readU16(r);
-    ttf->head->ymax = readU16(r);
-    ttf->head->macStyle = readU16(r);
-    ttf->head->lowest_readable_size = readU16(r); //in pixels
-    ttf->head->dir_hint = readS16(r);
-    int loc_index = readS16(r); //used in 'loca' table
-    if(loc_index>1)
-       msg("<warning> loca index format %d unknown", loc_index);
-    U16 glyph_data_format = readS16(r);
-    if(glyph_data_format!=0)
-       msg("<warning> Font glyph data format unknown: %04x", glyph_data_format);
-    return loc_index;
+    if(ttf->os2)
+       free(ttf->os2);
+    ttf->os2=0;
 }
 
 }
 
-static void head_write(ttf_t*ttf, ttf_table_t*w, int loca_size)
-{
-    writeU32(w, 0x10000);
-    writeU32(w, 0x10000);
-    writeU32(w, 0); //checksum
-    writeU32(w, 0x5f0f3cf5); //magic
-    writeU16(w, ttf->head->flags);
-    writeU16(w, ttf->head->units_per_em);
-    writeU32(w, 0);writeU32(w, 0); //created
-    writeU32(w, 0);writeU32(w, 0); //modified
-    writeU16(w, ttf->head->xmin);
-    writeU16(w, ttf->head->ymin);
-    writeU16(w, ttf->head->xmax);
-    writeU16(w, ttf->head->ymax);
-    writeU16(w, ttf->head->macStyle);
-    writeU16(w, ttf->head->lowest_readable_size);
-    writeS16(w, ttf->head->dir_hint);
-    writeS16(w, loca_size); //loca index size (32 bit)
-    writeS16(w, 0); //glyph data format
-}
-static void head_dump(ttf_t*ttf)
-{
-    printf("head->flags: %d\n", ttf->head->flags);
-    printf("head->units_per_em: %d\n", ttf->head->units_per_em);
-    printf("head->xmin: %d\n", ttf->head->xmin);
-    printf("head->ymin: %d\n", ttf->head->ymin);
-    printf("head->xmax: %d\n", ttf->head->xmax);
-    printf("head->ymax: %d\n", ttf->head->ymax);
-    printf("head->macStyle: %d\n", ttf->head->macStyle);
-    printf("head->lowest_readable_size: %d\n", ttf->head->lowest_readable_size);
-    printf("head->dir_hint: %d\n", ttf->head->dir_hint);
-}
-static void head_delete(ttf_t*ttf)
+static table_maxp_t*maxp_new(ttf_t*ttf)
 {
 {
-    if(ttf->head) {
-       free(ttf->head);
-       ttf->head=0;
+    table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
+    int t;
+    if(ttf->num_glyphs) {
+       int max = 0;
+       for(t=0;t<ttf->num_glyphs;t++) {
+           if(ttf->glyphs[t].num_points>max)
+               max = ttf->glyphs[t].num_points;
+           int contours = 0;
+           int s;
+           for(s=0;s<ttf->glyphs[t].num_points;s++) {
+               if(ttf->glyphs[t].points[s].flags&GLYPH_CONTOUR_END)
+                   contours++;
+           }
+           if(maxp->maxContours < contours)
+               maxp->maxContours = contours;
+       }
+       maxp->maxPoints = max;
+
+       /* we don't generate composite glyphs yet */
+       maxp->maxComponentPoints = 0;
+       maxp->maxComponentContours = 0;
     }
     }
+    return maxp;
 }
 }
-
 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
 {
     U32 version = readU32(r);
 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
 {
     U32 version = readU32(r);
@@ -517,7 +626,10 @@ static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
     /* according to freetype, older fonts (version<0x10000) 
        apparently only contain the number of glyphs. this is
        rather rare, though. */
     /* according to freetype, older fonts (version<0x10000) 
        apparently only contain the number of glyphs. this is
        rather rare, though. */
-    if(version<0x10000) return 0;
+    if(version<0x10000 && r->size==6) return 0;
+
+    if(r->size<32)
+       msg("<warning> Truncated maxp table (version %d)", version);
 
     table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
     maxp->maxPoints = readU16(r);
 
     table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
     maxp->maxPoints = readU16(r);
@@ -535,10 +647,15 @@ static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
     maxp->maxComponentDepth = readU16(r);
     return maxp;
 }
     maxp->maxComponentDepth = readU16(r);
     return maxp;
 }
-
 static void maxp_write(ttf_t*ttf, ttf_table_t*w)
 {
     table_maxp_t*maxp = ttf->maxp;
 static void maxp_write(ttf_t*ttf, ttf_table_t*w)
 {
     table_maxp_t*maxp = ttf->maxp;
+    if(!maxp) {
+       /* version 0.5 simplified maxp table */
+       writeU32(w, 0x00005000);
+       writeU16(w, ttf->num_glyphs);
+       return;
+    }
     writeU32(w, 0x10000); //version
     writeU16(w, ttf->num_glyphs);
     writeU16(w, maxp->maxPoints);
     writeU32(w, 0x10000); //version
     writeU16(w, ttf->num_glyphs);
     writeU16(w, maxp->maxPoints);
@@ -555,7 +672,6 @@ static void maxp_write(ttf_t*ttf, ttf_table_t*w)
     writeU16(w, maxp->maxComponentElements);
     writeU16(w, maxp->maxComponentDepth);
 }
     writeU16(w, maxp->maxComponentElements);
     writeU16(w, maxp->maxComponentDepth);
 }
-
 static void maxp_dump(ttf_t*ttf)
 {
     table_maxp_t*maxp = ttf->maxp;
 static void maxp_dump(ttf_t*ttf)
 {
     table_maxp_t*maxp = ttf->maxp;
@@ -574,7 +690,6 @@ static void maxp_dump(ttf_t*ttf)
     printf("maxp->maxComponentElements: %d\n", maxp->maxComponentElements);
     printf("maxp->maxComponentDepth: %d\n", maxp->maxComponentDepth);
 }
     printf("maxp->maxComponentElements: %d\n", maxp->maxComponentElements);
     printf("maxp->maxComponentDepth: %d\n", maxp->maxComponentDepth);
 }
-
 static void maxp_delete(ttf_t*ttf)
 {
     if(ttf->maxp)
 static void maxp_delete(ttf_t*ttf)
 {
     if(ttf->maxp)
@@ -582,14 +697,33 @@ static void maxp_delete(ttf_t*ttf)
     ttf->maxp=0;
 }
 
     ttf->maxp=0;
 }
 
-
+static table_hea_t*hea_new(ttf_t*ttf)
+{
+    table_hea_t*hea = rfx_calloc(sizeof(table_hea_t));
+    if(ttf->num_glyphs) {
+       int t;
+       for(t=0;t<ttf->num_glyphs;t++) {
+           if(ttf->glyphs[t].advance > hea->advanceWidthMax)
+               hea->advanceWidthMax = ttf->glyphs[t].advance;
+           if(ttf->glyphs[t].xmin < ttf->hea->minLeftSideBearing)
+               ttf->hea->minLeftSideBearing = ttf->glyphs[t].xmin;
+           if(ttf->glyphs[t].xmax < ttf->hea->minRightSideBearing)
+               ttf->hea->minRightSideBearing = ttf->glyphs[t].xmax;
+           int width = ttf->glyphs[t].xmax - ttf->glyphs[t].xmin;
+           if(width > hea->xMaxExtent)
+               hea->xMaxExtent = width;
+       }
+       /* TODO: caret */
+    }
+    return hea;
+}
 static int hea_parse(memreader_t*r, ttf_t*ttf)
 {
     table_hea_t*hea = ttf->hea = rfx_calloc(sizeof(table_hea_t));
     U32 version = readU32(r);
 static int hea_parse(memreader_t*r, ttf_t*ttf)
 {
     table_hea_t*hea = ttf->hea = rfx_calloc(sizeof(table_hea_t));
     U32 version = readU32(r);
-    hea->ascent = readS16(r);
-    hea->descent = readS16(r);
-    hea->lineGap = readS16(r);
+    ttf->ascent = readS16(r);
+    ttf->descent = readS16(r);
+    ttf->lineGap = readS16(r);
     hea->advanceWidthMax = readU16(r);
     hea->minLeftSideBearing = readS16(r);
     hea->minRightSideBearing = readS16(r);
     hea->advanceWidthMax = readU16(r);
     hea->minLeftSideBearing = readS16(r);
     hea->minRightSideBearing = readS16(r);
@@ -612,14 +746,13 @@ static int hea_parse(memreader_t*r, ttf_t*ttf)
     }
     return num_advances;
 }
     }
     return num_advances;
 }
-
 static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances)
 {
     table_hea_t*hea = ttf->hea;
     writeU32(w, 0x00010000);
 static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances)
 {
     table_hea_t*hea = ttf->hea;
     writeU32(w, 0x00010000);
-    writeS16(w, hea->ascent);
-    writeS16(w, hea->descent);
-    writeS16(w, hea->lineGap);
+    writeS16(w, ttf->ascent);
+    writeS16(w, ttf->descent);
+    writeS16(w, ttf->lineGap);
     writeU16(w, hea->advanceWidthMax);
     writeS16(w, hea->minLeftSideBearing);
     writeS16(w, hea->minRightSideBearing);
     writeU16(w, hea->advanceWidthMax);
     writeS16(w, hea->minLeftSideBearing);
     writeS16(w, hea->minRightSideBearing);
@@ -638,10 +771,11 @@ static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances)
 static void hea_dump(ttf_t*ttf)
 {
     table_hea_t*hea = ttf->hea;
 static void hea_dump(ttf_t*ttf)
 {
     table_hea_t*hea = ttf->hea;
+    if(!hea) return;
     const char*dir = ttf->is_vertical?"v":"h";
     const char*dir = ttf->is_vertical?"v":"h";
-    printf("%shea->ascent: %d\n", dir, hea->ascent);
-    printf("%shea->descent: %d\n", dir, hea->descent);
-    printf("%shea->lineGap: %d\n", dir, hea->lineGap);
+    printf("%shea->ascent: %d\n", dir, ttf->ascent);
+    printf("%shea->descent: %d\n", dir, ttf->descent);
+    printf("%shea->lineGap: %d\n", dir, ttf->lineGap);
     printf("%shea->advanceWidthMax: %d\n", dir, hea->advanceWidthMax);
     printf("%shea->minLeftSideBearing: %d\n", dir, hea->minLeftSideBearing);
     printf("%shea->minRightSideBearing: %d\n", dir, hea->minRightSideBearing);
     printf("%shea->advanceWidthMax: %d\n", dir, hea->advanceWidthMax);
     printf("%shea->minLeftSideBearing: %d\n", dir, hea->minLeftSideBearing);
     printf("%shea->minRightSideBearing: %d\n", dir, hea->minRightSideBearing);
@@ -658,7 +792,7 @@ static void hea_delete(ttf_t*ttf)
     }
 }
 
     }
 }
 
-static void hmtx_parse(memreader_t*r, ttf_t*ttf, int num_advances)
+static void mtx_parse(memreader_t*r, ttf_t*ttf, int num_advances)
 {
     U16 old_advance = 0;
     int t;
 {
     U16 old_advance = 0;
     int t;
@@ -701,21 +835,30 @@ static int mtx_write(ttf_t*ttf, ttf_table_t*w)
     }
     return num_advances;
 }
     }
     return num_advances;
 }
+
 static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size)
 {
     int t;
     int num = ttf->num_glyphs+1;
     U32*locations = rfx_calloc(num*sizeof(U32));
 static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size)
 {
     int t;
     int num = ttf->num_glyphs+1;
     U32*locations = rfx_calloc(num*sizeof(U32));
+    U32 lastloc = 0;
+    U32 loc = 0;
+    char warn_unsorted = 1;
     if(size) {
        if(num*4 > r->size) {
     if(size) {
        if(num*4 > r->size) {
-           msg("<warning> Short 'loca' table (32 bit)");
+           msg("<warning> Short 'loca' table (32 bit): %d/%d", r->size/4, num);
            num=r->size/4;
        }
        if(num*4 < r->size) {
            msg("<warning> Extraneous data (%d bytes) in 'loca' table (32 bit)", r->size-num*4);
        }
        for(t=0;t<num;t++) {
            num=r->size/4;
        }
        if(num*4 < r->size) {
            msg("<warning> Extraneous data (%d bytes) in 'loca' table (32 bit)", r->size-num*4);
        }
        for(t=0;t<num;t++) {
-           locations[t] = readU32(r);
+           locations[t] = loc = readU32(r);
+           if(lastloc > loc && warn_unsorted) {
+               msg("<warning> Unsorted 'loca' table (32 bit)");
+               warn_unsorted=0;
+           }
+           lastloc = loc;
        }
     } else {
        if(num*2 > r->size) {
        }
     } else {
        if(num*2 > r->size) {
@@ -726,7 +869,12 @@ static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size)
            msg("<warning> Extraneous data (%d bytes) in 'loca' table (16 bit)", r->size-num*2);
        }
        for(t=0;t<num;t++) {
            msg("<warning> Extraneous data (%d bytes) in 'loca' table (16 bit)", r->size-num*2);
        }
        for(t=0;t<num;t++) {
-           locations[t] = readU16(r)*2;
+           locations[t] = loc = readU16(r)*2;
+           if(lastloc > loc && warn_unsorted) {
+               msg("<warning> Unsorted 'loca' table");
+               warn_unsorted=0;
+           }
+           lastloc = loc;
        }
     }
     return locations;
        }
     }
     return locations;
@@ -754,6 +902,7 @@ static int loca_write(ttf_t*ttf, ttf_table_t*w, U32*locations)
        return 0;
     }
 }
        return 0;
     }
 }
+
 static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int glyphnr)
 {
     ttfglyph_t*glyph = &ttf->glyphs[glyphnr];
 static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int glyphnr)
 {
     ttfglyph_t*glyph = &ttf->glyphs[glyphnr];
@@ -863,11 +1012,14 @@ static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int gl
 static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
 {
     int t;
 static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
 {
     int t;
-    char warn_about_compound_glyphs=1;
+    char warn_about_compound_glyphs=0;
     for(t=0;t<ttf->num_glyphs;t++) {
        INIT_READ(r, rr->mem, rr->size, loca[t]);
     for(t=0;t<ttf->num_glyphs;t++) {
        INIT_READ(r, rr->mem, rr->size, loca[t]);
+       if(loca[t]==loca[t+1] || loca[t]==r.size)
+           continue; //empty glyph
        if(r.pos+10>r.size) {
        if(r.pos+10>r.size) {
-           msg("<warning> Unexpected end of glyph array (or bad loca entry %d/%d)", loca[t], r.size);
+           msg("<warning> Truncated glyph entry %d/%d (or bad loca entry %d/%d, next loca: %d)", 
+                   t, ttf->num_glyphs, loca[t], r.size, loca[t+1]);
            break;
        }
        S16 num_contours = readS16(&r);
            break;
        }
        S16 num_contours = readS16(&r);
@@ -887,7 +1039,6 @@ static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
     }
 
 }
     }
 
 }
-
 void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
 {
     /* endpoints array */
 void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
 {
     /* endpoints array */
@@ -979,7 +1130,6 @@ void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
        else if(dy) writeS16(w, dy);
     }
 }
        else if(dy) writeS16(w, dy);
     }
 }
-    
 U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
 {
     U32*locations = malloc(sizeof(U32)*(ttf->num_glyphs+1));
 U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
 {
     U32*locations = malloc(sizeof(U32)*(ttf->num_glyphs+1));
@@ -1016,6 +1166,7 @@ U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
 }
 void glyf_dump(ttf_t* ttf)
 {
 }
 void glyf_dump(ttf_t* ttf)
 {
+    if(!ttf->glyphs) return;
     int t;
     for(t=0;t<ttf->num_glyphs;t++) {
        ttfglyph_t*g = &ttf->glyphs[t];
     int t;
     for(t=0;t<ttf->num_glyphs;t++) {
        ttfglyph_t*g = &ttf->glyphs[t];
@@ -1034,7 +1185,6 @@ void glyf_dump(ttf_t* ttf)
            hexdump(g->code, g->code_size, "  ");
     }
 }
            hexdump(g->code, g->code_size, "  ");
     }
 }
-
 void glyf_delete(ttf_t* ttf)
 {
     if(!ttf->glyphs) 
 void glyf_delete(ttf_t* ttf)
 {
     if(!ttf->glyphs) 
@@ -1064,7 +1214,6 @@ static void grow_unicode(ttf_t*ttf, int index)
     }
     ttf->unicode_size = size;
 }
     }
     ttf->unicode_size = size;
 }
-
 void cmap_parse(memreader_t*r, ttf_t*ttf)
 {
     readU16(r); // version (0)
 void cmap_parse(memreader_t*r, ttf_t*ttf)
 {
     readU16(r); // version (0)
@@ -1134,8 +1283,9 @@ void cmap_parse(memreader_t*r, ttf_t*ttf)
                U16 delta = readU16(&r_delta);
                U16 range = readU16(&r_range);
                if(start==0xffff && end==0xffff && delta==1) {
                U16 delta = readU16(&r_delta);
                U16 range = readU16(&r_range);
                if(start==0xffff && end==0xffff && delta==1) {
-                   /* this is a common occurence in fonts which explicitly map
-                      "unicode undefined" (0xffff) to "glyph undefined" (0).
+                   /* this is a common (maybe even required) occurence in fonts 
+                      which explicitly map "unicode undefined" (0xffff) to 
+                      "glyph undefined" (0).
                       We don't want to blow our unicode table up to 65536 just
                       because of this, so ignore this entry.
                     */
                       We don't want to blow our unicode table up to 65536 just
                       because of this, so ignore this entry.
                     */
@@ -1157,7 +1307,6 @@ void cmap_parse(memreader_t*r, ttf_t*ttf)
        }
     }
 }
        }
     }
 }
-
 static int segment_size(unicode_t*unicode, int pos, int size)
 {
     int s;
 static int segment_size(unicode_t*unicode, int pos, int size)
 {
     int s;
@@ -1177,7 +1326,6 @@ static int segment_size(unicode_t*unicode, int pos, int size)
        return size-1;
     return s;
 }
        return size-1;
     return s;
 }
-
 void cmap_write(ttf_t* ttf, ttf_table_t*w)
 {
     writeU16(w, 0);  //version
 void cmap_write(ttf_t* ttf, ttf_table_t*w)
 {
     writeU16(w, 0);  //version
@@ -1212,6 +1360,9 @@ void cmap_write(ttf_t* ttf, ttf_table_t*w)
        pos = s+1;
        num_segments++;
     }
        pos = s+1;
        num_segments++;
     }
+
+    num_segments++; // account for 0xffff mapping
+
     int t;
     int end_pos = w->len;
     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
     int t;
     int end_pos = w->len;
     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
@@ -1223,8 +1374,8 @@ void cmap_write(ttf_t* ttf, ttf_table_t*w)
     int range_pos = w->len;
     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //range 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>>8;
-    w->data[num_segments_pos+1]=num_segments;
+    w->data[num_segments_pos]=(num_segments*2)>>8;
+    w->data[num_segments_pos+1]=(num_segments*2);
 
     pos=0;
     num_segments = 0;
 
     pos=0;
     num_segments = 0;
@@ -1265,6 +1416,18 @@ void cmap_write(ttf_t* ttf, ttf_table_t*w)
        num_segments++;
        pos = end+1;
     }
        num_segments++;
        pos = end+1;
     }
+
+    /* write out a mapping from 0xffff to 0- seems to be required
+       by some libraries (e.g. fonttools) */
+    w->data[end_pos++]=0xff;
+    w->data[end_pos++]=0xff;
+    w->data[start_pos++]=0xff;
+    w->data[start_pos++]=0xff;
+    w->data[delta_pos++]=0;
+    w->data[delta_pos++]=1;
+    w->data[range_pos++]=0;
+    w->data[range_pos++]=0;
+
     w->data[length_pos]=(w->len-20)>>8;
     w->data[length_pos+1]=w->len-20;
 }
     w->data[length_pos]=(w->len-20)>>8;
     w->data[length_pos+1]=w->len-20;
 }
@@ -1321,7 +1484,7 @@ static int ttf_parse_tables(ttf_t*ttf)
        table = ttf_find_table(ttf, TAG_HMTX);
        if(table) {
            INIT_READ(m, table->data, table->len, 0);
        table = ttf_find_table(ttf, TAG_HMTX);
        if(table) {
            INIT_READ(m, table->data, table->len, 0);
-           hmtx_parse(&m, ttf, num_advances);
+           mtx_parse(&m, ttf, num_advances);
             ttf_table_delete(ttf, table);
        }
     } else {
             ttf_table_delete(ttf, table);
        }
     } else {
@@ -1335,7 +1498,7 @@ static int ttf_parse_tables(ttf_t*ttf)
            table = ttf_find_table(ttf, TAG_VMTX);
            if(table) {
                INIT_READ(m, table->data, table->len, 0);
            table = ttf_find_table(ttf, TAG_VMTX);
            if(table) {
                INIT_READ(m, table->data, table->len, 0);
-               hmtx_parse(&m, ttf, num_advances);
+               mtx_parse(&m, ttf, num_advances);
                ttf_table_delete(ttf, table);
            }
        } else {
                ttf_table_delete(ttf, table);
            }
        } else {
@@ -1368,7 +1531,7 @@ static int ttf_parse_tables(ttf_t*ttf)
 static void ttf_collapse_tables(ttf_t*ttf)
 {
     ttf_table_t*table;
 static void ttf_collapse_tables(ttf_t*ttf)
 {
     ttf_table_t*table;
-    
+   
     table = ttf_addtable(ttf, TAG_MAXP);
     maxp_write(ttf, table);
     maxp_delete(ttf);
     table = ttf_addtable(ttf, TAG_MAXP);
     maxp_write(ttf, table);
     maxp_delete(ttf);
@@ -1409,7 +1572,13 @@ static void ttf_collapse_tables(ttf_t*ttf)
     head_delete(ttf);
 }
 
     head_delete(ttf);
 }
 
-ttf_t* load_ttf(void*data, int length)
+ttf_t*ttf_new()
+{
+    ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
+    ttf->version = VERSION_1_0;
+    return ttf;
+}
+ttf_t* ttf_load(void*data, int length)
 {
     INIT_READ(r,data,length, 0);
 
 {
     INIT_READ(r,data,length, 0);
 
@@ -1475,7 +1644,7 @@ ttf_t* load_ttf(void*data, int length)
            ttf_table_t*table = ttf_addtable(ttf, tag);
            table->data = mem;
            table->len = table->memsize = len;
            ttf_table_t*table = ttf_addtable(ttf, tag);
            table->data = mem;
            table->len = table->memsize = len;
-           
+#if 0
            U32 checksum2 = ttf_table_checksum(table);
            if(checksum2!=checksum) {
                msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x", 
            U32 checksum2 = ttf_table_checksum(table);
            if(checksum2!=checksum) {
                msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x", 
@@ -1483,7 +1652,7 @@ ttf_t* load_ttf(void*data, int length)
                        (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
                        len, checksum2, checksum);
            }
                        (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
                        len, checksum2, checksum);
            }
-           
+#endif
        }
     }
     free(table_data);
        }
     }
     free(table_data);
@@ -1493,7 +1662,17 @@ ttf_t* load_ttf(void*data, int length)
 
     return ttf;
 }
 
     return ttf;
 }
-
+void ttf_create_truetype_tables(ttf_t*ttf)
+{
+    if(!ttf->head) 
+       ttf->head = head_new(ttf);
+    if(!ttf->maxp) 
+       ttf->maxp = maxp_new(ttf);
+    if(!ttf->hea)
+       ttf->hea = hea_new(ttf);
+    if(!ttf->os2)
+       ttf->os2 = os2_new(ttf);
+}
 ttf_table_t* ttf_write(ttf_t*ttf)
 {
     ttf_collapse_tables(ttf);
 ttf_table_t* ttf_write(ttf_t*ttf)
 {
     ttf_collapse_tables(ttf);
@@ -1562,7 +1741,6 @@ ttf_table_t* ttf_write(ttf_t*ttf)
     checksum2[3] = checksum>>0;
     return file;
 }
     checksum2[3] = checksum>>0;
     return file;
 }
-
 void ttf_save(ttf_t*ttf, const char*filename)
 {
     ttf_table_t* t = ttf_write(ttf);
 void ttf_save(ttf_t*ttf, const char*filename)
 {
     ttf_table_t* t = ttf_write(ttf);
@@ -1575,7 +1753,6 @@ void ttf_save(ttf_t*ttf, const char*filename)
     fclose(fi);
     ttf_table_delete(0, t);
 }
     fclose(fi);
     ttf_table_delete(0, t);
 }
-
 void ttf_dump(ttf_t*ttf)
 {
     msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
 void ttf_dump(ttf_t*ttf)
 {
     msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
@@ -1621,13 +1798,13 @@ int main(int argn, const char*argv[])
        filename = argv[1];
     //msg("<notice> Loading %s", filename);
     memfile_t*m = memfile_open(filename);
        filename = argv[1];
     //msg("<notice> Loading %s", filename);
     memfile_t*m = memfile_open(filename);
-    ttf_t*ttf = load_ttf(m->data, m->len);
+    ttf_t*ttf = ttf_load(m->data, m->len);
     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);
     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, "comic2.ttf");
+    ttf_save(ttf, "output.ttf");
     ttf_destroy(ttf);
     return 0;
 
     ttf_destroy(ttf);
     return 0;
 
index a5ca523..73bd35c 100644 (file)
--- a/lib/ttf.h
+++ b/lib/ttf.h
@@ -54,7 +54,6 @@ typedef struct _table_os2 {
     S16 xAvgCharWidth;
     U16 usWeightClass;
     U16 usWidthClass;
     S16 xAvgCharWidth;
     U16 usWeightClass;
     U16 usWidthClass;
-    U16 fsType;
     U16 ySubscriptXSize;
     U16 ySubscriptYSize;
     U16 ySubscriptXOffset;
     U16 ySubscriptXSize;
     U16 ySubscriptYSize;
     U16 ySubscriptXOffset;
@@ -77,7 +76,6 @@ typedef struct _table_os2 {
     U8 panose_Midline;
     U8 panose_XHeight;
     U32 ulCharRange[4];
     U8 panose_Midline;
     U8 panose_XHeight;
     U32 ulCharRange[4];
-    U8 achVendID[4];
 
     U16 fsSelection;
     U16 fsFirstCharIndex;
 
     U16 fsSelection;
     U16 fsFirstCharIndex;
@@ -103,9 +101,6 @@ typedef struct _table_os2 {
 
 typedef struct _table_hea
 {
 
 typedef struct _table_hea
 {
-    S16 ascent;
-    S16 descent;
-    S16 lineGap;
     U16 advanceWidthMax;
     S16 minLeftSideBearing;
     S16 minRightSideBearing;
     U16 advanceWidthMax;
     S16 minLeftSideBearing;
     S16 minRightSideBearing;
@@ -154,6 +149,11 @@ typedef struct _ttf {
 
     U16 flags;
     char is_vertical;
 
     U16 flags;
     char is_vertical;
+
+    S16 ascent;
+    S16 descent;
+    S16 lineGap;
+
     int num_glyphs;
     ttfglyph_t*glyphs;
     
     int num_glyphs;
     ttfglyph_t*glyphs;
     
@@ -164,7 +164,11 @@ typedef struct _ttf {
 } ttf_t;
 
 
 } ttf_t;
 
 
-ttf_t*load_ttf(void*data, int length);
+ttf_t*ttf_new();
+ttf_t*ttf_load(void*data, int length);
 ttf_table_t*ttf_addtable(ttf_t*ttf, U32 tag);
 ttf_table_t*ttf_addtable(ttf_t*ttf, U32 tag);
+void ttf_create_truetype_tables(ttf_t*ttf);
+void ttf_dump(ttf_t*ttf);
+void ttf_save(ttf_t*ttf, const char*filename);
 
 #endif
 
 #endif