more ttf bug fixes
[swftools.git] / lib / ttf.c
1 /* ttf.c
2    Parser and writer for truetype font files.
3
4    Part of the swftools package.
5    
6    Copyright (c) 2010 Matthias Kramm <kramm@quiss.org> 
7  
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <memory.h>
25 #include "log.h"
26 #include "os.h"
27 #include "q.h"
28 #include "mem.h"
29 #include "ttf.h"
30
31 #define TTCFTAG 0x74746366
32
33 #define OPENTYPE 0x4f54544f
34 #define TRUETYPE_MACOS 0x74727565
35 #define VERSION_1_0 0x00010000
36
37 #define TAG_OS2 0x4f532f32
38 #define TAG_CMAP 0x636d6170
39 #define TAG_GLYF 0x676c7966 //required for non opentype
40 #define TAG_HEAD 0x68656164 //required
41 #define TAG_HHEA 0x68686561 //required
42 #define TAG_HMTX 0x686d7478 //required
43 #define TAG_VHEA 0x86686561
44 #define TAG_VMTX 0x866d7478
45 #define TAG_KERN 0x6b65726e
46 #define TAG_LOCA 0x6c6f6361 //required for non opentype
47 #define TAG_MAXP 0x6d617870 //required
48 #define TAG_NAME 0x6e616d65
49 #define TAG_POST 0x706f7374
50 #define TAG_CFF  0x43464620 //required for opentype
51
52 /* TODO:
53     fpgm - assembly instructions
54     prep - assembly instructions
55     cvt - constant value table
56     gasp - gridfitting procedure
57 */
58
59 static U32 checksum_block(U8*_data, int len)
60 {
61     U32 sum = 0;
62     U8*data = (U8*)_data;
63
64     int pos;
65     int len_minus_4 = len-4;
66     for(pos=0;pos<=len_minus_4;pos+=4) {
67         sum += data[pos]<<24|data[pos+1]<<16|data[pos+2]<<8|data[pos+3];
68     }
69     int left = len-pos;
70     if(left == 1) sum+= data[pos+0]<<24;
71     if(left == 2) sum+= data[pos+0]<<24|data[pos+1]<<16;
72     if(left == 3) sum+= data[pos+0]<<24|data[pos+1]<<16|data[pos+2]<<8;
73     return sum;
74 }
75
76 typedef struct _memreader {
77     U8*mem;
78     int pos;
79     int size;
80 } memreader_t;
81
82 static U8 readU8(memreader_t*r)
83 {
84     return r->mem[r->pos++];
85 }
86 static inline U16 readU16(memreader_t*r)
87 {
88     if(r->pos+2>r->size) return 0;
89     U16 val = r->mem[r->pos]<<8|
90               r->mem[r->pos+1];
91     r->pos += 2;
92     return val;
93 }
94 static S16 readS16(memreader_t*r)
95 {
96     return (S16)readU16(r);
97 }
98 static U32 readU32(memreader_t*r)
99 {
100     if(r->pos+4>r->size) return 0;
101     U32 val = r->mem[r->pos]<<24|
102               r->mem[r->pos+1]<<16|
103               r->mem[r->pos+2]<<8|
104               r->mem[r->pos+3];
105     r->pos += 4;
106     return val;
107 }
108 static void readBlock(memreader_t*r, void*dest, int len)
109 {
110     int remaining = r->size-r->pos;
111     if(len > remaining) {
112         memcpy(dest, r->mem+r->pos, remaining);
113         memset(dest+remaining, 0, len - remaining);
114         r->pos += remaining;
115     } else {
116         memcpy(dest, r->mem+r->pos, len);
117         r->pos += len;
118     }
119 }
120 #define INIT_READ(r,data,length,pos) memreader_t r = {(data),(pos),(length)};
121
122 static void expand(ttf_table_t*w, int newsize)
123 {
124     int v1 = (newsize+63)&~63;
125     int v2 = w->len + w->len / 2;
126     w->memsize = v1>v2?v1:v2;
127     w->data = rfx_realloc(w->data, w->memsize);
128 }
129 static inline void writeU8(ttf_table_t*w, unsigned char b)
130 {
131     if(w->memsize<w->len+1)
132         expand(w, w->len+1);
133     w->data[w->len++] = b;
134 }
135 static inline void writeU16(ttf_table_t*w, unsigned short v)
136 {
137     if(w->memsize<w->len+2)
138         expand(w, w->len+2);
139     w->data[w->len++] = v>>8;
140     w->data[w->len++] = v;
141 }
142 #define writeS16 writeU16
143 static inline void writeU32(ttf_table_t*w, unsigned long v)
144 {
145     if(w->memsize<w->len+4)
146         expand(w, w->len+4);
147     w->data[w->len++] = v>>24;
148     w->data[w->len++] = v>>16;
149     w->data[w->len++] = v>>8;
150     w->data[w->len++] = v;
151 }
152 static inline void writeBlock(ttf_table_t*w, void*data, int len)
153 {
154     if(w->memsize<w->len+len)
155         expand(w, w->len+len);
156     memcpy(w->data+w->len, data, len);
157     w->len += len;
158 }
159
160 ttf_table_t*ttf_table_new(U32 id)
161 {
162     ttf_table_t*t = rfx_calloc(sizeof(ttf_table_t));
163     t->id = id;
164     return t;
165 }
166
167 ttf_table_t*ttf_addtable(ttf_t*ttf, U32 id)
168 {
169     ttf_table_t*t = ttf_table_new(id);
170
171     ttf_table_t*before,*after=0;
172     for(before=ttf->tables; before&&before->id<id; before=before->next) {
173         after=before;
174     }
175     if(before && before->id == id) {
176         msg("<error> Error: duplicate table %08x", id);
177         free(before->data);
178         before->data = 0;
179         before->len = 0;
180         return before;
181     }
182     
183     if(!after) {
184         t->next = ttf->tables;
185         ttf->tables = t;
186     } else {
187         t->prev = after;
188         t->next = after->next;
189         after->next = t;
190     }
191     if(t->next)
192         t->next->prev = t;
193     return t;
194 }
195 ttf_table_t*ttf_find_table(ttf_t*ttf, U32 id)
196 {
197     ttf_table_t*table = ttf->tables;
198     while(table) {
199         if(table->id == id) 
200             return table;
201         table = table->next;
202     }
203     return 0;
204 }
205 void ttf_table_delete(ttf_t*ttf, ttf_table_t*table)
206 {
207     if(ttf && ttf->tables == table) {
208         ttf->tables = table->next;
209     }
210     if(table->prev) 
211         table->prev->next = table->next;
212     if(table->next) 
213         table->next->prev = table->prev;
214     free(table->data);
215     free(table);
216 }
217 U32 ttf_table_checksum(ttf_table_t*t)
218 {
219     U32 checksum = checksum_block(t->data, t->len);
220     if(t->id==TAG_HEAD && t->len>=12) {
221         /* the checksum for the HEAD table is calculated by masking out
222            the checksumadjust field */
223         U32 adjust = t->data[8]<<24|t->data[9]<<16|t->data[10]<<8|t->data[11];
224         checksum -= adjust;
225     }
226     return checksum;
227 }
228 static U8 printable(U8 a)
229 {
230     if(a<32 || a==127) return '.';
231     else return a;
232 }
233 static void hexdump(U8*data, int len, const char*prefix)
234 {
235     int t;
236     char ascii[32];
237     printf("%s    -=> ",prefix);
238     for(t=0;t<len;t++) {
239         printf("%02x ", data[t]);
240         ascii[t&15] = printable(data[t]);
241         if((t && ((t&15)==15)) || (t==len-1))
242         {
243             int s,p=((t)&15)+1;
244             ascii[p] = 0;
245             for(s=p-1;s<16;s++) {
246                 printf("   ");
247             }
248             if(t==len-1)
249                 printf(" %s\n", ascii);
250             else
251                 printf(" %s\n%s    -=> ",ascii,prefix);
252         }
253     }
254 }
255 static void ttf_table_dump(ttf_table_t*t, const char*prefix)
256 {
257     if(!t) return;
258     hexdump(t->data, t->len, prefix);
259 }
260
261 static table_head_t*head_new(ttf_t*ttf)
262 {
263     table_head_t*head = rfx_calloc(sizeof(table_head_t));
264     head->units_per_em = 1024;
265     int t;
266     if(ttf->num_glyphs) {
267         head->xmin = ttf->glyphs[0].xmin;
268         head->ymin = ttf->glyphs[0].ymin;
269         head->xmax = ttf->glyphs[0].xmax;
270         head->ymax = ttf->glyphs[0].ymax;
271         for(t=1;t<ttf->num_glyphs;t++) {
272             if(ttf->glyphs[t].xmin < head->xmin) head->xmin = ttf->glyphs[t].xmin;
273             if(ttf->glyphs[t].ymin < head->ymin) head->ymin = ttf->glyphs[t].ymin;
274             if(ttf->glyphs[t].xmax > head->xmax) head->xmax = ttf->glyphs[t].xmax;
275             if(ttf->glyphs[t].ymax > head->ymax) head->ymax = ttf->glyphs[t].ymax;
276         }
277     }
278     head->macStyle = 0;
279     head->lowest_readable_size = 8; // not sure what font renderers actually do with this
280     head->dir_hint = 0;
281     return head;
282 }
283 static int head_parse(ttf_t*ttf, memreader_t*r)
284 {
285     ttf->head = rfx_calloc(sizeof(table_head_t));
286     U32 version = readU32(r);
287     if(version!=VERSION_1_0) 
288         msg("<warning> Font HEAD has unknown version %08x", version);
289     U32 revision = readU32(r);
290     U32 checksum2 = readU32(r);
291     U32 magic = readU32(r);
292     if(magic!=0x5f0f3cf5) 
293         msg("<warning> Font HEAD has unknown magic number %08x", magic);
294     ttf->head->flags = readU16(r);
295     ttf->head->units_per_em = readU16(r);
296     readU32(r);readU32(r); //created
297     readU32(r);readU32(r); //modified
298     ttf->head->xmin = readU16(r);
299     ttf->head->ymin = readU16(r);
300     ttf->head->xmax = readU16(r);
301     ttf->head->ymax = readU16(r);
302     ttf->head->macStyle = readU16(r);
303     ttf->head->lowest_readable_size = readU16(r); //in pixels
304     ttf->head->dir_hint = readS16(r);
305     int loc_index = readS16(r); //used in 'loca' table
306     if(loc_index>1)
307         msg("<warning> loca index format %d unknown", loc_index);
308     U16 glyph_data_format = readS16(r);
309     if(glyph_data_format!=0)
310         msg("<warning> Font glyph data format unknown: %04x", glyph_data_format);
311     if(r->pos < r->size) {
312         msg("<warning> Leftover bytes (%d) in HEAD tag", r->size - r->pos);
313     }
314     return loc_index;
315 }
316 static void head_write(ttf_t*ttf, ttf_table_t*w, int loca_size)
317 {
318     writeU32(w, 0x10000);
319     writeU32(w, 0x10000);
320     writeU32(w, 0); //checksum
321     writeU32(w, 0x5f0f3cf5); //magic
322     writeU16(w, ttf->head->flags);
323     writeU16(w, ttf->head->units_per_em);
324     writeU32(w, 0);writeU32(w, 0); //created
325     writeU32(w, 0);writeU32(w, 0); //modified
326     writeU16(w, ttf->head->xmin);
327     writeU16(w, ttf->head->ymin);
328     writeU16(w, ttf->head->xmax);
329     writeU16(w, ttf->head->ymax);
330     writeU16(w, ttf->head->macStyle);
331     writeU16(w, ttf->head->lowest_readable_size);
332     writeS16(w, ttf->head->dir_hint);
333     writeS16(w, loca_size); //loca index size (32 bit)
334     writeS16(w, 0); //glyph data format
335 }
336 static void head_dump(ttf_t*ttf)
337 {
338     printf("head->flags: %d\n", ttf->head->flags);
339     printf("head->units_per_em: %d\n", ttf->head->units_per_em);
340     printf("head->xmin: %d\n", ttf->head->xmin);
341     printf("head->ymin: %d\n", ttf->head->ymin);
342     printf("head->xmax: %d\n", ttf->head->xmax);
343     printf("head->ymax: %d\n", ttf->head->ymax);
344     printf("head->macStyle: %d\n", ttf->head->macStyle);
345     printf("head->lowest_readable_size: %d\n", ttf->head->lowest_readable_size);
346     printf("head->dir_hint: %d\n", ttf->head->dir_hint);
347 }
348 static void head_delete(ttf_t*ttf)
349 {
350     if(ttf->head) {
351         free(ttf->head);
352         ttf->head=0;
353     }
354 }
355
356 static table_os2_t*os2_new(ttf_t*ttf)
357 {
358     table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
359     if(ttf->num_glyphs) {
360         int average_width=0;
361         int t;
362         for(t=0;t<ttf->num_glyphs;t++) {
363             average_width += (ttf->glyphs[t].advance + ttf->glyphs[t].bearing);
364         }
365         os2->xAvgCharWidth = average_width / ttf->num_glyphs;
366     }
367
368     /* that's what everybody seems to fill in */
369     os2->usWeightClass = 400;
370     os2->usWidthClass = 5;
371    
372     if(ttf->head) {
373         int advance = (ttf->head->xmax - ttf->head->xmin)/2;
374         int height = (ttf->head->xmax - ttf->head->xmin);
375         int ymid = height/2;
376         /* I do believe a sane font rendering engine will actually use
377            the font advance here- the subscript/superscript position will
378            not be the same for each glyph */
379         os2->ySuperscriptXSize = os2->ySubscriptXSize = (ttf->head->xmax - ttf->head->xmin)/2;
380         os2->ySuperscriptYSize = os2->ySubscriptYSize = (ttf->head->ymax - ttf->head->ymin)/2;
381         os2->ySubscriptXOffset = advance;
382         os2->ySubscriptYOffset = 0;
383         os2->ySuperscriptXOffset = advance;
384         os2->ySuperscriptYOffset = (ttf->head->ymax - ttf->head->ymin)/2;
385         os2->yStrikeoutSize = ttf->head->units_per_em / 10;
386         os2->yStrikeoutPosition = ymid;
387         os2->usWinAscent = ttf->head->ymax;
388         os2->usWinDescent = ttf->head->ymin<0?0:ttf->head->ymin;
389         os2->sxHeight = ymid;
390         os2->sCapHeight = height*2/3;
391     }
392     os2->panose_Weight = 4;
393
394     /* strictly speaking we'd have to set 92/64 bits in these tables, depending on
395        what parts of the unicode table is filled. (e.g. bit 90 = tibetan). */
396     os2->ulCharRange[0] = 1;
397     os2->ulCharRange[1] = 0;
398     os2->ulCharRange[2] = 0;
399     os2->ulCharRange[3] = 0;
400     os2->ulCodePageRange1 = 1;
401     os2->ulCodePageRange2 = 0;
402
403     if(ttf->unicode_size) {
404         int min,max;
405         for(min=0;min<ttf->unicode_size;min++)
406             if(ttf->unicode[min]) break;
407         for(max=ttf->unicode_size-1;max>=0;max--)
408             if(ttf->unicode[max]) break;
409         if(min<=max) {
410             os2->fsFirstCharIndex = min;
411             os2->fsLastCharIndex = max;
412         }
413     }
414     os2->sTypoAscender = ttf->ascent;
415     os2->sTypoDescender = ttf->descent;
416     os2->sTypoLineGap = ttf->lineGap;
417
418     os2->usDefaultChar = 0;
419     os2->usBreakChar = (ttf->unicode_size>0x20 && ttf->unicode[0x20])?0x20:0;
420     os2->usMaxContext = 0; // we don't use ligatures yet
421     return os2;
422 }
423 static table_os2_t*os2_parse(memreader_t*r)
424 {
425     table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
426     U16 version = readU16(r);
427     /* 0 = TrueType 1.5
428        1 = TrueType 1.66
429        2 = OpenType 1.2
430        3 = OpenType 1.4 */
431     if(version!=0 && version!=1 && version!=2 && version!=3)
432         msg("<warning> Unknown OS2 version: %04x", version);
433     os2->xAvgCharWidth = readS16(r);
434     os2->usWeightClass = readU16(r);
435     os2->usWidthClass = readU16(r);
436     readU16(r); //fstype
437     os2->ySubscriptXSize = readU16(r);
438     os2->ySubscriptYSize = readU16(r);
439     os2->ySubscriptXOffset = readU16(r);
440     os2->ySubscriptYOffset = readU16(r);
441     os2->ySuperscriptXSize = readU16(r);
442     os2->ySuperscriptYSize = readU16(r);
443     os2->ySuperscriptXOffset = readU16(r);
444     os2->ySuperscriptYOffset = readU16(r);
445     os2->yStrikeoutSize = readU16(r);
446     os2->yStrikeoutPosition = readU16(r);
447     os2->sFamilyClass = readU16(r);
448     os2->panose_FamilyType = readU8(r);
449     os2->panose_SerifStyle = readU8(r);
450     os2->panose_Weight = readU8(r);
451     os2->panose_Proportion = readU8(r);
452     os2->panose_Contrast = readU8(r);
453     os2->panose_StrokeVariation = readU8(r);
454     os2->panose_ArmStyle = readU8(r);
455     os2->panose_Letterform = readU8(r);
456     os2->panose_Midline = readU8(r);
457     os2->panose_XHeight = readU8(r);
458     os2->ulCharRange[0] = readU32(r);
459     os2->ulCharRange[1] = readU32(r);
460     os2->ulCharRange[2] = readU32(r);
461     os2->ulCharRange[3] = readU32(r);
462     readU32(r); //vendor
463     os2->fsSelection = readU16(r);
464     os2->fsFirstCharIndex = readU16(r);
465     os2->fsLastCharIndex = readU16(r);
466     os2->sTypoAscender = readS16(r);
467     os2->sTypoDescender = readS16(r);
468     os2->sTypoLineGap = readS16(r);
469     os2->usWinAscent = readU16(r);
470     os2->usWinDescent = readU16(r);
471     if(version<1) return os2;
472     os2->ulCodePageRange1 = readU32(r);
473     os2->ulCodePageRange2 = readU32(r);
474     if(version<2) return os2;
475     os2->sxHeight = readS16(r);
476     os2->sCapHeight = readS16(r);
477     os2->usDefaultChar = readU16(r);
478     os2->usBreakChar = readU16(r);
479     os2->usMaxContext = readU16(r);
480     
481     if(r->pos < r->size) {
482         msg("<warning> Leftover bytes (%d) in OS2 tag", r->size - r->pos);
483     }
484     return os2;
485 }
486 static void os2_write(ttf_t*ttf, ttf_table_t*w)
487 {
488     table_os2_t*os2 = ttf->os2;
489     U16 version=1;
490     if(os2->sxHeight|os2->sCapHeight|os2->usDefaultChar|os2->usBreakChar|os2->usMaxContext) {
491         version=2;
492     }
493     writeU16(w, version);
494     writeS16(w, os2->xAvgCharWidth);
495     writeU16(w, os2->usWeightClass);
496     writeU16(w, os2->usWidthClass);
497     writeU16(w, 0); //fstype
498     writeU16(w, os2->ySubscriptXSize);
499     writeU16(w, os2->ySubscriptYSize);
500     writeU16(w, os2->ySubscriptXOffset);
501     writeU16(w, os2->ySubscriptYOffset);
502     writeU16(w, os2->ySuperscriptXSize);
503     writeU16(w, os2->ySuperscriptYSize);
504     writeU16(w, os2->ySuperscriptXOffset);
505     writeU16(w, os2->ySuperscriptYOffset);
506     writeU16(w, os2->yStrikeoutSize);
507     writeU16(w, os2->yStrikeoutPosition);
508     writeU16(w, os2->sFamilyClass);
509     writeU8(w, os2->panose_FamilyType);
510     writeU8(w, os2->panose_SerifStyle);
511     writeU8(w, os2->panose_Weight);
512     writeU8(w, os2->panose_Proportion);
513     writeU8(w, os2->panose_Contrast);
514     writeU8(w, os2->panose_StrokeVariation);
515     writeU8(w, os2->panose_ArmStyle);
516     writeU8(w, os2->panose_Letterform);
517     writeU8(w, os2->panose_Midline);
518     writeU8(w, os2->panose_XHeight);
519     writeU32(w, os2->ulCharRange[0]);
520     writeU32(w, os2->ulCharRange[1]);
521     writeU32(w, os2->ulCharRange[2]);
522     writeU32(w, os2->ulCharRange[3]);
523     writeU32(w, 0x53434244); //vendor
524     writeU16(w, os2->fsSelection);
525     writeU16(w, os2->fsFirstCharIndex);
526     writeU16(w, os2->fsLastCharIndex);
527     writeS16(w, os2->sTypoAscender);
528     writeS16(w, os2->sTypoDescender);
529     writeS16(w, os2->sTypoLineGap);
530     writeU16(w, os2->usWinAscent);
531     writeU16(w, os2->usWinDescent);
532     if(version<1) return;
533     writeU32(w, os2->ulCodePageRange1);
534     writeU32(w, os2->ulCodePageRange2);
535     if(version<2) return;
536     writeS16(w, os2->sxHeight);
537     writeS16(w, os2->sCapHeight);
538     writeU16(w, os2->usDefaultChar);
539     writeU16(w, os2->usBreakChar);
540     writeU16(w, os2->usMaxContext);
541 }
542 static void os2_dump(ttf_t*ttf)
543 {
544     table_os2_t*os2 = ttf->os2;
545     if(!os2) return;
546     printf("os2->xAvgCharWidth: %d\n", os2->xAvgCharWidth);
547     printf("os2->usWeightClass: %d\n", os2->usWeightClass);
548     printf("os2->usWidthClass: %d\n", os2->usWidthClass);
549     printf("os2->ySubscriptXSize: %d\n", os2->ySubscriptXSize);
550     printf("os2->ySubscriptYSize: %d\n", os2->ySubscriptYSize);
551     printf("os2->ySubscriptXOffset: %d\n", os2->ySubscriptXOffset);
552     printf("os2->ySubscriptYOffset: %d\n", os2->ySubscriptYOffset);
553     printf("os2->ySuperscriptXSize: %d\n", os2->ySuperscriptXSize);
554     printf("os2->ySuperscriptYSize: %d\n", os2->ySuperscriptYSize);
555     printf("os2->ySuperscriptXOffset: %d\n", os2->ySuperscriptXOffset);
556     printf("os2->ySuperscriptYOffset: %d\n", os2->ySuperscriptYOffset);
557     printf("os2->yStrikeoutSize: %d\n", os2->yStrikeoutSize);
558     printf("os2->yStrikeoutPosition: %d\n", os2->yStrikeoutPosition);
559     printf("os2->sFamilyClass: %d\n", os2->sFamilyClass);
560     printf("os2->panose_FamilyType: %d\n", os2->panose_FamilyType);
561     printf("os2->panose_SerifStyle: %d\n", os2->panose_SerifStyle);
562     printf("os2->panose_Weight: %d\n", os2->panose_Weight);
563     printf("os2->panose_Proportion: %d\n", os2->panose_Proportion);
564     printf("os2->panose_Contrast: %d\n", os2->panose_Contrast);
565     printf("os2->panose_StrokeVariation: %d\n", os2->panose_StrokeVariation);
566     printf("os2->panose_ArmStyle: %d\n", os2->panose_ArmStyle);
567     printf("os2->panose_Letterform: %d\n", os2->panose_Letterform);
568     printf("os2->panose_Midline: %d\n", os2->panose_Midline);
569     printf("os2->panose_XHeight: %d\n", os2->panose_XHeight);
570     printf("os2->ulCharRange[0]: %d\n", os2->ulCharRange[0]);
571     printf("os2->ulCharRange[1]: %d\n", os2->ulCharRange[1]);
572     printf("os2->ulCharRange[2]: %d\n", os2->ulCharRange[2]);
573     printf("os2->ulCharRange[3]: %d\n", os2->ulCharRange[3]);
574     printf("os2->fsSelection: %d\n", os2->fsSelection);
575     printf("os2->fsFirstCharIndex: %d\n", os2->fsFirstCharIndex);
576     printf("os2->fsLastCharIndex: %d\n", os2->fsLastCharIndex);
577     printf("os2->sTypoAscender: %d\n", os2->sTypoAscender);
578     printf("os2->sTypoDescender: %d\n", os2->sTypoDescender);
579     printf("os2->sTypoLineGap: %d\n", os2->sTypoLineGap);
580     printf("os2->usWinAscent: %d\n", os2->usWinAscent);
581     printf("os2->usWinDescent: %d\n", os2->usWinDescent);
582     printf("os2->ulCodePageRange1: %d\n", os2->ulCodePageRange1);
583     printf("os2->ulCodePageRange2: %d\n", os2->ulCodePageRange2);
584     printf("os2->sxHeight: %d\n", os2->sxHeight);
585     printf("os2->sCapHeight: %d\n", os2->sCapHeight);
586     printf("os2->usDefaultChar: %d\n", os2->usDefaultChar);
587     printf("os2->usBreakChar: %d\n", os2->usBreakChar);
588     printf("os2->usMaxContext: %d\n", os2->usMaxContext);
589 }
590 static void os2_delete(ttf_t*ttf)
591 {
592     if(ttf->os2)
593         free(ttf->os2);
594     ttf->os2=0;
595 }
596
597 static table_maxp_t*maxp_new(ttf_t*ttf)
598 {
599     table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
600     int t;
601     if(ttf->num_glyphs) {
602         int max = 0;
603         for(t=0;t<ttf->num_glyphs;t++) {
604             if(ttf->glyphs[t].num_points>max)
605                 max = ttf->glyphs[t].num_points;
606             int contours = 0;
607             int s;
608             for(s=0;s<ttf->glyphs[t].num_points;s++) {
609                 if(ttf->glyphs[t].points[s].flags&GLYPH_CONTOUR_END)
610                     contours++;
611             }
612             if(maxp->maxContours < contours)
613                 maxp->maxContours = contours;
614         }
615         maxp->maxPoints = max;
616
617         /* we don't generate composite glyphs yet */
618         maxp->maxComponentPoints = 0;
619         maxp->maxComponentContours = 0;
620     }
621     return maxp;
622 }
623 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
624 {
625     U32 version = readU32(r);
626     ttf->num_glyphs = readU16(r);
627     /* according to freetype, older fonts (version<0x10000) 
628        apparently only contain the number of glyphs. this is
629        rather rare, though. */
630     if(version<0x10000 && r->size==6) return 0;
631
632     if(r->size<32)
633         msg("<warning> Truncated maxp table (version %d)", version);
634
635     table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
636     maxp->maxPoints = readU16(r);
637     maxp->maxContours = readU16(r);
638     maxp->maxComponentPoints = readU16(r);
639     maxp->maxComponentContours = readU16(r);
640     maxp->maxZones = readU16(r);
641     maxp->maxTwilightPoints = readU16(r);
642     maxp->maxStorage = readU16(r);
643     maxp->maxFunctionDefs = readU16(r);
644     maxp->maxInstructionDefs = readU16(r);
645     maxp->maxStackElements = readU16(r);
646     maxp->maxSizeOfInstructions = readU16(r);
647     maxp->maxComponentElements = readU16(r);
648     maxp->maxComponentDepth = readU16(r);
649     return maxp;
650 }
651 static void maxp_write(ttf_t*ttf, ttf_table_t*w)
652 {
653     table_maxp_t*maxp = ttf->maxp;
654     if(!maxp) {
655         /* version 0.5 simplified maxp table */
656         writeU32(w, 0x00005000);
657         writeU16(w, ttf->num_glyphs);
658         return;
659     }
660     writeU32(w, 0x10000); //version
661     writeU16(w, ttf->num_glyphs);
662     writeU16(w, maxp->maxPoints);
663     writeU16(w, maxp->maxContours);
664     writeU16(w, maxp->maxComponentPoints);
665     writeU16(w, maxp->maxComponentContours);
666     writeU16(w, maxp->maxZones);
667     writeU16(w, maxp->maxTwilightPoints);
668     writeU16(w, maxp->maxStorage);
669     writeU16(w, maxp->maxFunctionDefs);
670     writeU16(w, maxp->maxInstructionDefs);
671     writeU16(w, maxp->maxStackElements);
672     writeU16(w, maxp->maxSizeOfInstructions);
673     writeU16(w, maxp->maxComponentElements);
674     writeU16(w, maxp->maxComponentDepth);
675 }
676 static void maxp_dump(ttf_t*ttf)
677 {
678     table_maxp_t*maxp = ttf->maxp;
679     if(!maxp) return;
680     printf("maxp->maxPoints: %d\n", maxp->maxPoints);
681     printf("maxp->maxContours: %d\n", maxp->maxContours);
682     printf("maxp->maxComponentPoints: %d\n", maxp->maxComponentPoints);
683     printf("maxp->maxComponentContours: %d\n", maxp->maxComponentContours);
684     printf("maxp->maxZones: %d\n", maxp->maxZones);
685     printf("maxp->maxTwilightPoints: %d\n", maxp->maxTwilightPoints);
686     printf("maxp->maxStorage: %d\n", maxp->maxStorage);
687     printf("maxp->maxFunctionDefs: %d\n", maxp->maxFunctionDefs);
688     printf("maxp->maxInstructionDefs: %d\n", maxp->maxInstructionDefs);
689     printf("maxp->maxStackElements: %d\n", maxp->maxStackElements);
690     printf("maxp->maxSizeOfInstructions: %d\n", maxp->maxSizeOfInstructions);
691     printf("maxp->maxComponentElements: %d\n", maxp->maxComponentElements);
692     printf("maxp->maxComponentDepth: %d\n", maxp->maxComponentDepth);
693 }
694 static void maxp_delete(ttf_t*ttf)
695 {
696     if(ttf->maxp)
697         free(ttf->maxp);
698     ttf->maxp=0;
699 }
700
701 static table_hea_t*hea_new(ttf_t*ttf)
702 {
703     table_hea_t*hea = rfx_calloc(sizeof(table_hea_t));
704     if(ttf->num_glyphs) {
705         int t;
706         for(t=0;t<ttf->num_glyphs;t++) {
707             if(ttf->glyphs[t].advance > hea->advanceWidthMax)
708                 hea->advanceWidthMax = ttf->glyphs[t].advance;
709             if(ttf->glyphs[t].xmin < hea->minLeftSideBearing)
710                 hea->minLeftSideBearing = ttf->glyphs[t].xmin;
711             if(ttf->glyphs[t].xmax < hea->minRightSideBearing)
712                 hea->minRightSideBearing = ttf->glyphs[t].xmax;
713             int width = ttf->glyphs[t].xmax - ttf->glyphs[t].xmin;
714             if(width > hea->xMaxExtent)
715                 hea->xMaxExtent = width;
716         }
717         /* TODO: caret */
718     }
719     return hea;
720 }
721 static int hea_parse(memreader_t*r, ttf_t*ttf)
722 {
723     table_hea_t*hea = ttf->hea = rfx_calloc(sizeof(table_hea_t));
724     U32 version = readU32(r);
725     ttf->ascent = readS16(r);
726     ttf->descent = readS16(r);
727     ttf->lineGap = readS16(r);
728     hea->advanceWidthMax = readU16(r);
729     hea->minLeftSideBearing = readS16(r);
730     hea->minRightSideBearing = readS16(r);
731     hea->xMaxExtent = readS16(r);
732     hea->caretSlopeRise = readS16(r);
733     hea->caretSlopeRun = readS16(r);
734     hea->caretOffset = readS16(r);
735     readS16(r); //reserved[0]
736     readS16(r); //reserved[1]
737     readS16(r); //reserved[2]
738     readS16(r); //reserved[3]
739     S16 metricDataFormat = readS16(r); //should be 0
740     if(metricDataFormat!=0) {
741         msg("<warning> Unknown metric format %d", metricDataFormat);
742     }
743     int num_advances = readU16(r);
744     if(num_advances > ttf->num_glyphs) {
745         msg("<warning> bad number of horizontal metrics: %d", num_advances);
746         num_advances = ttf->num_glyphs;
747     }
748     return num_advances;
749 }
750 static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances)
751 {
752     table_hea_t*hea = ttf->hea;
753     writeU32(w, 0x00010000);
754     writeS16(w, ttf->ascent);
755     writeS16(w, ttf->descent);
756     writeS16(w, ttf->lineGap);
757     writeU16(w, hea->advanceWidthMax);
758     writeS16(w, hea->minLeftSideBearing);
759     writeS16(w, hea->minRightSideBearing);
760     writeS16(w, hea->xMaxExtent);
761     writeS16(w, hea->caretSlopeRise);
762     writeS16(w, hea->caretSlopeRun);
763     writeS16(w, hea->caretOffset);
764     writeS16(w, 0); //reserved
765     writeS16(w, 0); //reserved
766     writeS16(w, 0); //reserved
767     writeS16(w, 0); //reserved
768     writeS16(w, 0); //metricDataFormat
769     writeU16(w, num_advances);
770     return hea;
771 }
772 static void hea_dump(ttf_t*ttf)
773 {
774     table_hea_t*hea = ttf->hea;
775     if(!hea) return;
776     const char*dir = ttf->is_vertical?"v":"h";
777     printf("%shea->ascent: %d\n", dir, ttf->ascent);
778     printf("%shea->descent: %d\n", dir, ttf->descent);
779     printf("%shea->lineGap: %d\n", dir, ttf->lineGap);
780     printf("%shea->advanceWidthMax: %d\n", dir, hea->advanceWidthMax);
781     printf("%shea->minLeftSideBearing: %d\n", dir, hea->minLeftSideBearing);
782     printf("%shea->minRightSideBearing: %d\n", dir, hea->minRightSideBearing);
783     printf("%shea->xMaxExtent: %d\n", dir, hea->xMaxExtent);
784     printf("%shea->caretSlopeRise: %d\n", dir, hea->caretSlopeRise);
785     printf("%shea->caretSlopeRun: %d\n", dir, hea->caretSlopeRun);
786     printf("%shea->caretOffset: %d\n", dir, hea->caretOffset);
787 }
788 static void hea_delete(ttf_t*ttf)
789 {
790     if(ttf->hea) {
791         free(ttf->hea);
792         ttf->hea=0;
793     }
794 }
795
796 static void mtx_parse(memreader_t*r, ttf_t*ttf, int num_advances)
797 {
798     U16 old_advance = 0;
799     int t;
800     if(num_advances > r->size/4)
801         num_advances = r->size/4;
802     for(t=0;t<num_advances;t++) {
803         old_advance = ttf->glyphs[t].advance = readU16(r);
804         ttf->glyphs[t].bearing = readS16(r);
805     }
806     int rest = (r->size - num_advances*4)/2;
807     if(ttf->num_glyphs < num_advances+rest) {
808         rest = ttf->num_glyphs-num_advances;
809     }
810     for(t=0;t<rest;t++) {
811         ttf->glyphs[t].advance = old_advance; 
812         ttf->glyphs[t].bearing = readS16(r);
813     }
814 }
815 static int mtx_write(ttf_t*ttf, ttf_table_t*w)
816 {
817     int num_advances = ttf->num_glyphs;
818     if(ttf->num_glyphs>=2) {
819         int t;
820         for(t=ttf->num_glyphs-1;t>0;t--) {
821             if(ttf->glyphs[t-1].advance !=
822                ttf->glyphs[t].advance) break;
823         }
824         /* we need to store all individual advances as well
825            as one entry for the constant */
826         num_advances = t+1;
827     }
828
829     int t;
830     for(t=0;t<num_advances;t++) {
831         writeU16(w, ttf->glyphs[t].advance);
832         writeU16(w, ttf->glyphs[t].bearing);
833     }
834     for(;t<ttf->num_glyphs;t++) {
835         writeU16(w, ttf->glyphs[t].bearing);
836     }
837     return num_advances;
838 }
839
840 static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size)
841 {
842     int t;
843     int num = ttf->num_glyphs+1;
844     U32*locations = rfx_calloc(num*sizeof(U32));
845     U32 lastloc = 0;
846     U32 loc = 0;
847     char warn_unsorted = 1;
848     if(size) {
849         if(num*4 > r->size) {
850             msg("<warning> Short 'loca' table (32 bit): %d/%d", r->size/4, num);
851             num=r->size/4;
852         }
853         if(num*4 < r->size) {
854             msg("<warning> Extraneous data (%d bytes) in 'loca' table (32 bit)", r->size-num*4);
855         }
856         for(t=0;t<num;t++) {
857             locations[t] = loc = readU32(r);
858             if(lastloc > loc && warn_unsorted) {
859                 msg("<warning> Unsorted 'loca' table (32 bit)");
860                 warn_unsorted=0;
861             }
862             lastloc = loc;
863         }
864     } else {
865         if(num*2 > r->size) {
866             msg("<warning> Short 'loca' table (16 bit)");
867             num=r->size/2;
868         }
869         if(num*2 < r->size) {
870             msg("<warning> Extraneous data (%d bytes) in 'loca' table (16 bit)", r->size-num*2);
871         }
872         for(t=0;t<num;t++) {
873             locations[t] = loc = readU16(r)*2;
874             if(lastloc > loc && warn_unsorted) {
875                 msg("<warning> Unsorted 'loca' table");
876                 warn_unsorted=0;
877             }
878             lastloc = loc;
879         }
880     }
881     return locations;
882 }
883 static int loca_write(ttf_t*ttf, ttf_table_t*w, U32*locations)
884 {
885     int t;
886     char use_32bit = 0;
887     for(t=0;t<=ttf->num_glyphs;t++) {
888         if(locations[t]>=0x20000 || (locations[t]&1)) {
889             use_32bit = 1;
890             break;
891         }
892     }
893
894     if(use_32bit) {
895         for(t=0;t<=ttf->num_glyphs;t++) {
896             writeU32(w, locations[t]);
897         }
898         return 1;
899     } else {
900         for(t=0;t<=ttf->num_glyphs;t++) {
901             writeU16(w, locations[t]/2);
902         }
903         return 0;
904     }
905 }
906
907 static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int glyphnr)
908 {
909     ttfglyph_t*glyph = &ttf->glyphs[glyphnr];
910
911     U16*endpoints = 0;
912     if(num_contours>0) {
913         endpoints = malloc(sizeof(U16)*num_contours);
914         int s;
915         int lastpos = -1;
916         for(s=0;s<num_contours;s++) {
917             int pos = endpoints[s] = readU16(r);
918             if(pos<=lastpos) {
919                 msg("<warning> Unsorted endpoints array (len:%d) last=%d now=%d", s, pos, lastpos);
920             }
921             lastpos = pos;
922         }
923     }
924     U16 code_len = readU16(r);
925     if(code_len) {
926         glyph->code = malloc(sizeof(U16)*code_len);
927         readBlock(r, glyph->code, code_len);
928         glyph->code_size = code_len;
929     }
930
931     if(!endpoints) 
932         return 1;
933
934     /*msg("<notice> TTF Glyph %d) code_size=%d num_contours=%d glyph->num_points=%d %d/%d/%d/%d", 
935             glyphnr, code_len, num_contours, glyph->num_points,
936             xmin, ymin, xmax, ymax);*/
937     INIT_READ(fx, r->mem, r->size, r->pos);
938     INIT_READ(fy, r->mem, r->size, r->pos);
939     
940     glyph->num_points = endpoints[num_contours-1] + 1;
941     glyph->points = rfx_calloc(sizeof(ttfpoint_t)*glyph->num_points);
942
943     /* parse flag array (1st pass- to determine start of coordinates) */
944     int num=0;
945     while(num<glyph->num_points) {
946         U8 flag = readU8(r);
947         if(flag&0xc0) {
948             msg("<error> Bad flags in glyph outline: %02x (at pos %d)", flag, num);
949             free(glyph->points);
950             glyph->points = 0;
951             glyph->num_points = 0;
952             return 0;
953         }
954         int count = 1;
955         if(flag & 0x08) 
956             count += readU8(r);
957         if(count+num>glyph->num_points) {
958             msg("<warning> Bad count (%d) in glyph (%d) (at pos %d)", count, glyphnr, num);
959             count = glyph->num_points-num;
960         }
961         num+=count;
962     }
963
964     /* parse flag array (2nd pass) and x coordinates */
965     num=0;
966     int x = 0;
967     char is_start=1;
968     int contour_pos=0;
969     int bytepos = r->pos;
970     while(num<glyph->num_points) {
971         U8 flag = readU8(&fx);
972         int count = flag&8?readU8(&fx)+1:1;
973         count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
974         do {
975             char is_end=0;
976             if(contour_pos<num_contours && num==endpoints[contour_pos]) {
977                 contour_pos++;
978                 is_end=1;
979             }
980             int oldx = x;
981             if((flag&0x12) == 0x12) x += readU8(r);
982             else if((flag&0x12) == 0x02) x -= readU8(r);
983             else if((flag&0x12) == 0x00) x += readS16(r);
984             
985             glyph->points[num].x = x;
986             U8 f = flag&GLYPH_ON_CURVE;
987             if(is_start) f|=GLYPH_CONTOUR_START;
988             if(is_end) f|=GLYPH_CONTOUR_END;
989             glyph->points[num].flags = f;
990             num++;
991             is_start = is_end;
992         } while(--count);
993     }
994     
995     /* parse flag array (3rd pass) and y coordinates */
996     num=0;
997     int y = 0;
998     while(num<glyph->num_points) {
999         U8 flag = readU8(&fy);
1000         int count = flag&8?readU8(&fy)+1:1;
1001         count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
1002         do {
1003             if((flag&0x24) == 0x24) y += readU8(r);
1004             else if((flag&0x24) == 0x04) y -= readU8(r);
1005             else if((flag&0x24) == 0x00) y += readS16(r);
1006             glyph->points[num].y = y;
1007             num++;
1008         } while(--count);
1009     }
1010     free(endpoints);
1011     return 1;
1012 }
1013 static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
1014 {
1015     int t;
1016     char warn_about_compound_glyphs=0;
1017     for(t=0;t<ttf->num_glyphs;t++) {
1018         INIT_READ(r, rr->mem, rr->size, loca[t]);
1019         if(loca[t]==loca[t+1] || loca[t]==r.size)
1020             continue; //empty glyph
1021         if(r.pos+10>r.size) {
1022             msg("<warning> Truncated glyph entry %d/%d (or bad loca entry %d/%d, next loca: %d)", 
1023                     t, ttf->num_glyphs, loca[t], r.size, loca[t+1]);
1024             break;
1025         }
1026         S16 num_contours = readS16(&r);
1027         ttf->glyphs[t].xmin = readS16(&r);
1028         ttf->glyphs[t].ymin = readS16(&r);
1029         ttf->glyphs[t].xmax = readS16(&r);
1030         ttf->glyphs[t].ymax = readS16(&r);
1031         
1032         if(num_contours<0) {
1033             if(warn_about_compound_glyphs)
1034                 msg("<error> Compound glyphs not supported yet");
1035             warn_about_compound_glyphs=0;
1036         } else {
1037             if(!parse_simple_glyph(ttf, &r, num_contours, t))
1038                 return;
1039         }
1040     }
1041
1042 }
1043 void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
1044 {
1045     /* endpoints array */
1046     int s;
1047     for(s=0;s<g->num_points;s++) {
1048         if(g->points[s].flags&GLYPH_CONTOUR_END)
1049             writeU16(w, s);
1050     }
1051     
1052     /* bytecode */
1053     writeU16(w, g->code_size);
1054     if(g->code_size)
1055         writeBlock(w, g->code, g->code_size);
1056
1057     /* flags */
1058     int lastx=0;
1059     int lasty=0;
1060     int lastflag=-1;
1061     int flagcount=0;
1062     for(s=0;s<g->num_points;s++) {
1063         ttfpoint_t*p = &g->points[s];
1064         int dx = p->x - lastx;
1065         int dy = p->y - lasty;
1066         U8 flags = p->flags&GLYPH_ON_CURVE;
1067         if(!dx) {
1068             flags|=0x10;
1069         } else if(dx<0 && dx>=-255) {
1070             flags|=0x02;
1071         } else if(dx>0 && dx<=255) {
1072             flags|=0x12;
1073         }
1074         if(!dy) {
1075             flags|=0x20;
1076         } else if(dy<0 && dy>=-255) {
1077             flags|=0x04;
1078         } else if(dy>0 && dy<=255) {
1079             flags|=0x24;
1080         }
1081         if(flags == lastflag && flagcount<255) {
1082             flagcount++;
1083         } else {
1084             if(lastflag>=0) {
1085                 if(flagcount) {
1086                     writeU8(w, lastflag|8);
1087                     writeU8(w, flagcount);
1088                 } else {
1089                     writeU8(w, lastflag);
1090                 }
1091             }
1092             lastflag = flags;
1093             flagcount = 0;
1094         }
1095         lastx = p->x;
1096         lasty = p->y;
1097     }
1098     if(lastflag>=0) {
1099         if(flagcount) {
1100             writeU8(w, lastflag|8);
1101             writeU8(w, flagcount);
1102         } else {
1103             writeU8(w, lastflag);
1104         }
1105     }
1106     /* coordinates */
1107     lastx=0;
1108     int bytepos = w->len;
1109     for(s=0;s<g->num_points;s++) {
1110         ttfpoint_t*p = &g->points[s];
1111         int dx = p->x - lastx;
1112         if(dx>32767 || dx<-32768) {
1113             msg("<error> Coordinate overflow in glyph");
1114         }
1115         lastx = p->x;
1116         if(dx>0 && dx<=255) writeU8(w, dx);
1117         else if(dx<0 && dx>=-255) writeU8(w, -dx);
1118         else if(dx) writeS16(w, dx);
1119     }
1120
1121     lasty=0;
1122     for(s=0;s<g->num_points;s++) {
1123         ttfpoint_t*p = &g->points[s];
1124         int dy = p->y - lasty;
1125         if(dy>32767 || dy<-32768) {
1126             msg("<error> Coordinate overflow in glyph");
1127         }
1128         lasty = p->y;
1129         if(dy>0 && dy<=255) writeU8(w, dy);
1130         else if(dy<0 && dy>=-255) writeU8(w, -dy);
1131         else if(dy) writeS16(w, dy);
1132     }
1133 }
1134 U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
1135 {
1136     U32*locations = malloc(sizeof(U32)*(ttf->num_glyphs+1));
1137     int t;
1138     for(t=0;t<ttf->num_glyphs;t++) {
1139         locations[t] = w->len;
1140         ttfglyph_t*g = &ttf->glyphs[t];
1141         int s;
1142         int num_contours = 0;
1143         for(s=0;s<g->num_points;s++) {
1144             if(g->points[s].flags&GLYPH_CONTOUR_END)
1145                 num_contours++;
1146         }
1147         writeS16(w, num_contours?num_contours:1);
1148         writeS16(w, g->xmin);
1149         writeS16(w, g->ymin);
1150         writeS16(w, g->xmax);
1151         writeS16(w, g->ymax);
1152         
1153         if(!num_contours) {
1154             /* some ttf parsers can't deal with zero contours, so in the case
1155                of an empty glyph, write a single point (0,0) */
1156             writeU16(w, 0); //endpoint of 1st contour
1157             writeU16(w, g->code_size);
1158             if(g->code_size)
1159                 writeBlock(w, g->code, g->code_size);
1160             writeU8(w, 0x31); //flag (xy=(0,0),on curve)
1161         } else {
1162             write_simple_glyph(w, g);
1163         }
1164     }
1165     locations[t] = w->len;
1166     return locations;
1167 }
1168 void glyf_dump(ttf_t* ttf)
1169 {
1170     if(!ttf->glyphs) return;
1171     int t;
1172     for(t=0;t<ttf->num_glyphs;t++) {
1173         ttfglyph_t*g = &ttf->glyphs[t];
1174         printf("glyph %d)\n", t);
1175         printf("  advance=%d\n", g->advance);
1176         printf("  bearing=%d\n", g->bearing);
1177         printf("  bbox=(%d/%d/%d/%d)\n", g->xmin, g->ymin, g->xmax, g->ymax);
1178         printf("  points=(");
1179         int s;
1180         for(s=0;s<g->num_points;s++) {
1181             if(s) printf(",");
1182             printf("%d/%d/0x%02x", g->points[s].x, g->points[s].y, g->points[s].flags);
1183         }
1184         printf(")\n");
1185         if(g->code_size) 
1186             hexdump(g->code, g->code_size, "  ");
1187     }
1188 }
1189 void glyf_delete(ttf_t* ttf)
1190 {
1191     if(!ttf->glyphs) 
1192         return;
1193     int t;
1194     for(t=0;t<ttf->num_glyphs;t++) {
1195         if(ttf->glyphs[t].code) {
1196             free(ttf->glyphs[t].code);
1197             ttf->glyphs[t].code = 0;
1198         }
1199         if(ttf->glyphs[t].points) {
1200             free(ttf->glyphs[t].points);
1201             ttf->glyphs[t].points = 0;
1202         }
1203     }
1204     free(ttf->glyphs);ttf->glyphs=0;
1205 }
1206
1207 static void grow_unicode(ttf_t*ttf, int index)
1208 {
1209     int size = index+1;
1210     if(!ttf->unicode) {
1211         ttf->unicode = rfx_calloc(sizeof(ttf->unicode[0])*size);
1212     } else if(ttf->unicode_size<size) {
1213         ttf->unicode = rfx_realloc(ttf->unicode, sizeof(ttf->unicode[0])*size);
1214         memset(ttf->unicode+ttf->unicode_size, 0, sizeof(ttf->unicode[0])*(size - ttf->unicode_size));
1215     }
1216     ttf->unicode_size = size;
1217 }
1218 void cmap_parse(memreader_t*r, ttf_t*ttf)
1219 {
1220     readU16(r); // version (0)
1221     int num_subtables = readU16(r);
1222     int t;
1223     char warn=1;
1224     if(r->pos+num_subtables*8 > r->size) {
1225         msg("<warning> CMap overflow");
1226         num_subtables = (r->size-r->pos)/8;
1227     }
1228     unicode_t*data = 0;
1229     for(t=0;t<num_subtables;t++) {
1230         U16 platform = readU16(r);
1231         U16 encoding = readU16(r);
1232         U32 offset = readU32(r);
1233         if(offset>r->size) {
1234             msg("<warning> CMAP table %d %d is out of bounds (%d)", platform, encoding, offset);
1235             continue;
1236         }
1237
1238         int is_unicode = platform==0 ||
1239                          platform==3 && encoding == 1 ||
1240                          platform==3 && encoding == 10;
1241
1242         if(!is_unicode) 
1243             continue;
1244
1245         INIT_READ(t, r->mem, r->size, offset);
1246         U16 format = readU16(&t);
1247         int length = readU16(&t);
1248         U16 language = readU16(&t);
1249
1250         if(language)
1251             msg("<warning> Language code %02x in unicode mapping", language);
1252
1253         int num = 0;
1254         if(format == 0) {
1255             num = length-6;
1256             if(t.pos+length > t.size) {
1257                 msg("<warning> overflow in format 0 cmap table");
1258                 num = t.size-t.pos;
1259             }
1260             data = malloc(num*sizeof(unicode_t));
1261             int s;
1262             grow_unicode(ttf, num);
1263             for(s=0;s<num;s++) {
1264                 ttf->unicode[s] = readU8(&t);
1265             }
1266         } else if(format == 4) {
1267             U16 segment_count = readU16(&t); 
1268             if(segment_count&1) {
1269                 msg("<error> Bad segmentx2 count %d", segment_count);
1270                 continue;
1271             }
1272             segment_count>>=1;
1273             readU16(&t); //searchrange
1274             readU16(&t); //entry selector
1275             readU16(&t); //range shift
1276             INIT_READ(r_end, t.mem, t.size, t.pos);
1277             INIT_READ(r_start, t.mem, t.size, t.pos+2+segment_count*2);
1278             INIT_READ(r_delta, t.mem, t.size, t.pos+2+segment_count*4);
1279             INIT_READ(r_range, t.mem, t.size, t.pos+2+segment_count*6);
1280             int glyphmap_start = t.pos+2+segment_count*8;
1281             int glyphmap_size = t.size - glyphmap_start;
1282             int s;
1283             for(s=0;s<segment_count;s++) {
1284                 U16 start = readU16(&r_start);
1285                 U16 end = readU16(&r_end);
1286                 U16 delta = readU16(&r_delta);
1287                 U16 range = readU16(&r_range);
1288                 if(start==0xffff && end==0xffff && delta==1) {
1289                     /* this is a common (maybe even required) occurence in fonts 
1290                        which explicitly map "unicode undefined" (0xffff) to 
1291                        "glyph undefined" (0).
1292                        We don't want to blow our unicode table up to 65536 just
1293                        because of this, so ignore this entry.
1294                      */
1295                     continue;
1296                 }
1297                 grow_unicode(ttf, end);
1298                 int u;
1299                 if(!range) {
1300                     for(u=start;u<=end;u++) {
1301                         ttf->unicode[u] = (u + delta) & 0xffff;
1302                     }
1303                 } else {
1304                     int pos = r_range.pos-2+range;
1305                     if(warn && pos+end-start+1 > t.size) {
1306                         msg("<warning> glyphmap index out of bounds (%d-%d/%d)", pos, pos+end-start, t.size);
1307                         warn=0;
1308                     }
1309                     INIT_READ(g, t.mem, t.size, pos);
1310                     for(u=start;u<=end;u++) {
1311                         ttf->unicode[u] = readU16(&g);
1312                     }
1313                 }
1314             }
1315         }
1316     }
1317 }
1318 static int segment_size(unicode_t*unicode, int pos, int size)
1319 {
1320     int s;
1321     int count=0;
1322     for(s=pos;s<size;s++) {
1323         if(!unicode[s])
1324             count++;
1325         if(count>4) {
1326             /* a segment costs us 8 bytes, so for more than 4 consecutive 
1327                zero entries (16 bit each) in the glyph index array,
1328                it pays off to start a new segment */
1329             break;
1330         }
1331     }
1332     s -= count; // go to the last filled in entry
1333     if(s==size)
1334         return size-1;
1335     return s;
1336 }
1337 void cmap_write(ttf_t* ttf, ttf_table_t*w)
1338 {
1339     writeU16(w, 0);  //version
1340     writeU16(w, 2);  //two tables
1341
1342     writeU16(w, 0);  //platform (unicode)
1343     writeU16(w, 3);  //encoding (unicode 2.0)
1344     writeU32(w, 20); //offset
1345
1346     writeU16(w, 3);  //platform (windows)
1347     writeU16(w, 1);  //encoding (unicode basic multilingual plane UCS-2)
1348     writeU32(w, 20); //offset
1349
1350     writeU16(w, 4); // format=4
1351     int length_pos = w->len;
1352     writeU16(w, 0); // length: we don't know yet
1353     writeU16(w, 0); // language (n/a for unicode)
1354     int num_segments_pos = w->len;
1355     writeU16(w, 0); //number of segments: we don't know yet either
1356     writeU16(w, 0); //searchrange
1357     writeU16(w, 0); //entry selector
1358     writeU16(w, 0); //range shift
1359
1360     int pos=0;
1361     int num_segments=0;
1362     while(pos < ttf->unicode_size) {
1363         if(!ttf->unicode[pos]) {
1364             pos++;
1365             continue;
1366         }
1367         int s = segment_size(ttf->unicode, pos, ttf->unicode_size);
1368         pos = s+1;
1369         num_segments++;
1370     }
1371
1372     num_segments++; // account for 0xffff mapping
1373
1374     int glyphmap_start = w->len+2+num_segments*8;
1375     
1376     int t;
1377     int end_pos = w->len;
1378     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
1379     writeU16(w, 0); //reserved byte
1380     int start_pos = w->len;
1381     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //start array
1382     int delta_pos = w->len;
1383     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //delta array
1384     int range_pos = w->len;
1385     for(t=0;t<num_segments;t++) {writeU16(w, 0);} //range array
1386             
1387     w->data[num_segments_pos]=(num_segments*2)>>8;
1388     w->data[num_segments_pos+1]=(num_segments*2);
1389     
1390     pos=0;
1391     num_segments = 0;
1392     while(pos < ttf->unicode_size) {
1393         if(!ttf->unicode[pos]) {
1394             pos++;
1395             continue;
1396         }
1397         U16 end = segment_size(ttf->unicode, pos, ttf->unicode_size);
1398         w->data[end_pos++]=end>>8;
1399         w->data[end_pos++]=end;
1400         w->data[start_pos++]=pos>>8;
1401         w->data[start_pos++]=pos;
1402         int s;
1403         U16 delta = ttf->unicode[pos]-pos;
1404         char do_delta=1;
1405         for(s=pos+1;s<=end;s++) {
1406             U16 delta2 = ttf->unicode[s]-s;
1407             if(delta2!=delta) {
1408                 do_delta=0;
1409                 break;
1410             }
1411         }
1412         U16 range;
1413         if(do_delta) {
1414             range = 0;
1415         } else {
1416             delta = 0;
1417             range = w->len - range_pos;
1418             for(s=pos;s<=end;s++) {
1419                 writeU16(w, ttf->unicode[s]);
1420             }
1421         }
1422         w->data[delta_pos++]=delta>>8;
1423         w->data[delta_pos++]=delta;
1424         w->data[range_pos++]=range>>8;
1425         w->data[range_pos++]=range;
1426         num_segments++;
1427         pos = end+1;
1428     }
1429
1430     /* write out a mapping from 0xffff to 0- seems to be required
1431        by some libraries (e.g. fonttools) */
1432     w->data[end_pos++]=0xff;
1433     w->data[end_pos++]=0xff;
1434     w->data[start_pos++]=0xff;
1435     w->data[start_pos++]=0xff;
1436     w->data[delta_pos++]=0;
1437     w->data[delta_pos++]=1;
1438     w->data[range_pos++]=0;
1439     w->data[range_pos++]=0;
1440
1441     w->data[length_pos]=(w->len-20)>>8;
1442     w->data[length_pos+1]=w->len-20;
1443 }
1444 void cmap_delete(ttf_t*ttf)
1445 {
1446     if(ttf->unicode) {
1447         free(ttf->unicode);
1448         ttf->unicode=0;
1449     }
1450     ttf->unicode_size=0;
1451 }
1452 void name_parse(memreader_t*r, ttf_t*ttf)
1453 {
1454     U16 format = readU16(r);
1455     U16 count = readU16(r);
1456     U16 offset = readU16(r);
1457    
1458     int t;
1459     for(t=0;t<count;t++) {
1460         U16 platform = readU16(r);
1461         U16 encoding = readU16(r);
1462         U16 language = readU16(r);
1463         U16 name_id = readU16(r);
1464         U16 len = readU16(r);
1465         U16 offset_2 = readU16(r);
1466         if(name_id==4) {
1467             if(ttf->name)
1468                 free(ttf->name);
1469             ttf->name = strdup_n(&r->mem[offset+offset_2], len);
1470         }
1471     }
1472 }
1473 void name_write(ttf_t*ttf, ttf_table_t*table)
1474 {
1475     writeU16(table, 0); //format
1476     writeU16(table, 1); //count
1477     int offset = 18;
1478     writeU16(table, offset); //offset
1479
1480     writeU16(table, 1); //platform id
1481     writeU16(table, 0); //encoding id
1482     writeU16(table, 0); //language
1483     writeU16(table, 4); //4: full name
1484     int len = strlen(ttf->name);
1485     writeU16(table, len);
1486     writeU16(table, table->len+2 - offset);
1487     int t;
1488     for(t=0;t<len;t++) {
1489         writeU8(table, ttf->name[t]);
1490     }
1491 }
1492 void name_delete(ttf_t*ttf)
1493 {
1494     if(ttf->name) {
1495         free(ttf->name);
1496         ttf->name=0;
1497     }
1498 }
1499
1500 static table_post_t*post_new(ttf_t*ttf)
1501 {
1502     table_post_t*post = rfx_calloc(sizeof(table_post_t));
1503     return post;
1504 }
1505 void post_parse(memreader_t*r, ttf_t*ttf)
1506 {
1507     table_post_t*post = ttf->post = rfx_calloc(sizeof(table_post_t));
1508     U16 format = readU16(r);
1509     post->italic_angle = readU16(r);
1510     post->underline_position = readU16(r);
1511     post->underline_thickness = readU16(r);
1512     U16 is_monospaced = readU16(r);
1513     readU16(r); // min mem 42
1514     readU16(r);
1515     readU16(r); // min mem 1
1516     readU16(r);
1517 }
1518 void post_write(ttf_t*ttf, ttf_table_t*table)
1519 {
1520     table_post_t*post = ttf->post;
1521     writeU32(table, 0x00030000);
1522     writeU32(table, post->italic_angle);
1523     writeU16(table, post->underline_position);
1524     writeU16(table, post->underline_thickness);
1525     writeU32(table, 0); //is monospaced TODO
1526     writeU32(table, 0); //min mem 42
1527     writeU32(table, 0);
1528     writeU32(table, 0); //min mem 1
1529     writeU32(table, 0);
1530 }
1531 void post_delete(ttf_t*ttf)
1532 {
1533     if(ttf->post) {
1534         free(ttf->post);
1535         ttf->post = 0;
1536     }
1537 }
1538
1539 static int ttf_parse_tables(ttf_t*ttf)
1540 {
1541     ttf_table_t*table;
1542
1543     table = ttf_find_table(ttf, TAG_HEAD);
1544     if(!table) {
1545         msg("<error> Font has no head table");
1546         return 0;
1547     }
1548     INIT_READ(m, table->data, table->len, 0);
1549     int loc_index = head_parse(ttf, &m);
1550     ttf_table_delete(ttf, table);
1551     
1552     table = ttf_find_table(ttf, TAG_MAXP);
1553     if(!table) {
1554         msg("<error> Font has no maxp table");
1555         return 0;
1556     }
1557     INIT_READ(m2, table->data, table->len, 0);
1558     ttf->maxp = maxp_parse(ttf, &m2);
1559     ttf_table_delete(ttf, table);
1560     
1561     if(!ttf->num_glyphs) {
1562         msg("<error> Invalid number of characters");
1563         return 0;
1564     }
1565     ttf->glyphs = rfx_calloc(sizeof(ttfglyph_t)*ttf->num_glyphs);
1566
1567     table = ttf_find_table(ttf, TAG_OS2);
1568     if(table) {
1569         INIT_READ(m, table->data, table->len, 0);
1570         ttf->os2 = os2_parse(&m);
1571         ttf_table_delete(ttf, table);
1572     }
1573
1574     table = ttf_find_table(ttf, TAG_HHEA);
1575     if(table) {
1576         INIT_READ(m, table->data, table->len, 0);
1577         int num_advances = hea_parse(&m, ttf);
1578         ttf_table_delete(ttf, table);
1579         
1580         table = ttf_find_table(ttf, TAG_HMTX);
1581         if(table) {
1582             INIT_READ(m, table->data, table->len, 0);
1583             mtx_parse(&m, ttf, num_advances);
1584             ttf_table_delete(ttf, table);
1585         }
1586     } else {
1587         table = ttf_find_table(ttf, TAG_VHEA);
1588         if(table) {
1589             ttf->is_vertical=1;
1590             INIT_READ(m, table->data, table->len, 0);
1591             int num_advances = hea_parse(&m, ttf);
1592             ttf_table_delete(ttf, table);
1593
1594             table = ttf_find_table(ttf, TAG_VMTX);
1595             if(table) {
1596                 INIT_READ(m, table->data, table->len, 0);
1597                 mtx_parse(&m, ttf, num_advances);
1598                 ttf_table_delete(ttf, table);
1599             }
1600         } else {
1601             msg("<error> Font contains neither HHEA nor VHEA");
1602         }
1603     }
1604     table = ttf_find_table(ttf, TAG_LOCA);
1605     if(table) {
1606         INIT_READ(m, table->data, table->len, 0);
1607         U32*loca = loca_parse(&m, ttf, loc_index);
1608         ttf_table_delete(ttf, table);
1609         table = ttf_find_table(ttf, TAG_GLYF);
1610         if(table) {
1611             INIT_READ(m, table->data, table->len, 0);
1612             glyf_parse(&m, ttf, loca);
1613             ttf_table_delete(ttf, table);
1614         }
1615         free(loca);
1616     }
1617     
1618     table = ttf_find_table(ttf, TAG_CMAP);
1619     if(table) {
1620         INIT_READ(m, table->data, table->len, 0);
1621         cmap_parse(&m, ttf);
1622         ttf_table_delete(ttf, table);
1623     }
1624     
1625     table = ttf_find_table(ttf, TAG_NAME);
1626     if(table) {
1627         INIT_READ(m, table->data, table->len, 0);
1628         name_parse(&m, ttf);
1629         ttf_table_delete(ttf, table);
1630     }
1631
1632     table = ttf_find_table(ttf, TAG_POST);
1633     if(table) {
1634         INIT_READ(m, table->data, table->len, 0);
1635         post_parse(&m, ttf);
1636         ttf_table_delete(ttf, table);
1637     }
1638
1639     return 1;
1640 }
1641 static void ttf_collapse_tables(ttf_t*ttf)
1642 {
1643     ttf_table_t*table;
1644    
1645     table = ttf_addtable(ttf, TAG_MAXP);
1646     maxp_write(ttf, table);
1647     maxp_delete(ttf);
1648
1649     table = ttf_addtable(ttf, TAG_OS2);
1650     os2_write(ttf, table);
1651     os2_delete(ttf);
1652
1653     if(!ttf->is_vertical) {
1654         table = ttf_addtable(ttf, TAG_HMTX);
1655         int num_advances = mtx_write(ttf, table);
1656         table = ttf_addtable(ttf, TAG_HHEA);
1657         hea_write(ttf, table, num_advances);
1658     } else {
1659         table = ttf_addtable(ttf, TAG_VMTX);
1660         int num_advances = mtx_write(ttf, table);
1661         table = ttf_addtable(ttf, TAG_VHEA);
1662         hea_write(ttf, table, num_advances);
1663     }
1664         
1665     int loca_size=0;
1666     if(ttf->num_glyphs) {
1667         table = ttf_addtable(ttf, TAG_CMAP);
1668         cmap_write(ttf, table);
1669         cmap_delete(ttf);
1670
1671         table = ttf_addtable(ttf, TAG_GLYF);
1672         U32*locations = glyf_write(ttf, table);
1673         glyf_delete(ttf);
1674         
1675         table = ttf_addtable(ttf, TAG_LOCA);
1676         loca_size = loca_write(ttf, table, locations);
1677         free(locations);
1678     }
1679
1680     if(ttf->name) {
1681         table = ttf_addtable(ttf, TAG_NAME);
1682         name_write(ttf, table);
1683         name_delete(ttf);
1684     }
1685     if(ttf->post) {
1686         table = ttf_addtable(ttf, TAG_POST);
1687         post_write(ttf, table);
1688         post_delete(ttf);
1689     }
1690     
1691     table = ttf_addtable(ttf, TAG_HEAD);
1692     head_write(ttf, table, loca_size);
1693     head_delete(ttf);
1694 }
1695
1696 ttf_t*ttf_new()
1697 {
1698     ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1699     ttf->version = VERSION_1_0;
1700     return ttf;
1701 }
1702 ttf_t* ttf_load(void*data, int length)
1703 {
1704     INIT_READ(r,data,length, 0);
1705
1706     if(length<12) {
1707         msg("<error> Truncated Truetype file (%d bytes)", length);
1708         return 0;
1709     }
1710
1711     ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1712     ttf->version = readU32(&r);
1713     if(ttf->version == TTCFTAG) {
1714         /* a ttc collection is a number of truetype fonts
1715            packaged together */
1716         if(length<16) {
1717             msg("<error> Truncated TTC file (%d bytes)", length);
1718             return 0;
1719         }
1720         U32 ttcf_version = readU32(&r); // 0x00000100: v1.0, 0x00000200: v2.0, includes DSIG table
1721         U32 num_fonts = readU32(&r); // number of fonts
1722         U32 font1_position = readU32(&r);
1723         if(font1_position+12 > length) {\
1724             msg("<error> Truncated TTC file (%d bytes, first font at %d)", length, font1_position);
1725             return 0;
1726         }
1727         r.pos = font1_position;
1728         ttf->version = readU32(&r);
1729     }
1730     
1731     int num_tables = readU16(&r);
1732     
1733     readU16(&r); //search range
1734     readU16(&r); //entry selector
1735     readU16(&r); //range shift
1736
1737     if(num_tables*16 > length) {
1738         msg("<error> Truncated TTC file (table entries: %d)", num_tables);
1739         if(ttf->version != OPENTYPE && 
1740            ttf->version != TRUETYPE_MACOS && 
1741            ttf->version != VERSION_1_0) {
1742             // bad table length, weird version. This is probably not a ttf file.
1743             return 0;
1744         }
1745     }
1746
1747     U32*table_data = malloc(16*num_tables);
1748     int t;
1749     for(t=0;t<num_tables*4;t++) {
1750         table_data[t] = readU32(&r);
1751     }
1752     for(t=0;t<num_tables;t++) {
1753         U32 tag = table_data[t*4];
1754         U32 checksum = table_data[t*4+1];
1755         U32 pos = table_data[t*4+2];
1756         U32 len = table_data[t*4+3];
1757
1758         if(pos+len > length) {
1759             msg("<error> TTF Table %02x%02x%02x%02x outside of stream (pos %d)", (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, pos);
1760         } else {
1761             U8*mem = malloc(len);
1762             r.pos = pos;
1763             readBlock(&r, mem, len);
1764             
1765             ttf_table_t*table = ttf_addtable(ttf, tag);
1766             table->data = mem;
1767             table->len = table->memsize = len;
1768 #if 0
1769             U32 checksum2 = ttf_table_checksum(table);
1770             if(checksum2!=checksum) {
1771                 msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x", 
1772                         (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1773                         (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1774                         len, checksum2, checksum);
1775             }
1776 #endif
1777         }
1778     }
1779     free(table_data);
1780
1781     if(!ttf_parse_tables(ttf)) 
1782         return 0;
1783
1784     return ttf;
1785 }
1786 void ttf_create_truetype_tables(ttf_t*ttf)
1787 {
1788     if(!ttf->head) 
1789         ttf->head = head_new(ttf);
1790     if(!ttf->maxp) 
1791         ttf->maxp = maxp_new(ttf);
1792     if(!ttf->hea)
1793         ttf->hea = hea_new(ttf);
1794     if(!ttf->os2)
1795         ttf->os2 = os2_new(ttf);
1796     if(!ttf->post)
1797         ttf->post = post_new(ttf);
1798 }
1799 ttf_table_t* ttf_write(ttf_t*ttf)
1800 {
1801     ttf_collapse_tables(ttf);
1802    
1803     ttf_table_t*file = ttf_table_new(0);
1804     writeU32(file, VERSION_1_0);
1805
1806     /* write number of tables */
1807     int num_tables=0;
1808     ttf_table_t*t = ttf->tables;
1809     while(t) {
1810         num_tables++;
1811         t = t->next;
1812     }
1813     writeU16(file, num_tables);
1814     
1815     /* write search range */
1816     int tmp = num_tables;
1817     int search_range = 0;
1818     while(tmp) {
1819         search_range = tmp;
1820         tmp = tmp&(tmp-1);
1821     }
1822     tmp = search_range;
1823     search_range*=16;
1824     writeU16(file, search_range);
1825
1826     /* write entry selector */
1827     int entry_selector = 0;
1828     while(tmp>1) {
1829         tmp>>=1;
1830         entry_selector++;
1831     }
1832     writeU16(file, entry_selector);
1833
1834     /* write range shift */
1835     int range_shift = num_tables*16 - search_range;
1836     writeU16(file, range_shift);
1837
1838     /* write table dictionary */
1839     int table_dictionary_pos = file->len;
1840     int data_pos = file->len + num_tables*16;
1841     for(t=ttf->tables;t;t=t->next) {
1842         writeU32(file, t->id);
1843         writeU32(file, ttf_table_checksum(t));
1844         writeU32(file, data_pos);
1845         writeU32(file, t->len);
1846         data_pos += t->len;
1847         data_pos += (-t->len)&3; //pad
1848     }
1849
1850     /* write tables */
1851     int head_pos = 0;
1852     U8 zero[4]={0,0,0,0};
1853     for(t=ttf->tables;t;t=t->next) {
1854         if(t->id == TAG_HEAD)
1855             head_pos = file->len;
1856         writeBlock(file, t->data, t->len);
1857         writeBlock(file, zero, (-t->len)&3); //pad
1858     }
1859     U32 checksum = 0xb1b0afba - ttf_table_checksum(file);
1860     U8*checksum2 = file->data + head_pos + 8;
1861     checksum2[0] = checksum>>24;
1862     checksum2[1] = checksum>>16;
1863     checksum2[2] = checksum>>8;
1864     checksum2[3] = checksum>>0;
1865     return file;
1866 }
1867 void ttf_save(ttf_t*ttf, const char*filename)
1868 {
1869     ttf_table_t* t = ttf_write(ttf);
1870     FILE*fi = fopen(filename, "wb");
1871     if(!fi) {
1872         perror(filename);
1873         return;
1874     }
1875     fwrite(t->data, t->len, 1, fi);
1876     fclose(fi);
1877     ttf_table_delete(0, t);
1878 }
1879 void ttf_dump(ttf_t*ttf)
1880 {
1881     msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
1882     ttf_table_t*table = ttf->tables;
1883     while(table) {
1884         U32 tag = table->id;
1885         msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)", 
1886                 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, 
1887                 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
1888         table = table->next;
1889     }
1890     //ttf_table_dump(ttf_find_table(ttf, TAG_MAXP));
1891
1892     head_dump(ttf);
1893     hea_dump(ttf);
1894     os2_dump(ttf);
1895     maxp_dump(ttf);
1896     glyf_dump(ttf);
1897 }
1898 void ttf_destroy_tables(ttf_t*ttf)
1899 {
1900     ttf_table_t*table = ttf->tables;
1901     while(table) {
1902         ttf_table_t*next = table->next;
1903         free(table->data);
1904         free(table);
1905         table = next;
1906     }
1907     ttf->tables = 0;
1908 }
1909 void ttf_reduce(ttf_t*ttf)
1910 {
1911     ttf_destroy_tables(ttf);
1912 }
1913 void ttf_destroy(ttf_t*ttf)
1914 {
1915     ttf_destroy_tables(ttf);
1916     maxp_delete(ttf);
1917     os2_delete(ttf);
1918     head_delete(ttf);
1919     hea_delete(ttf);
1920     glyf_delete(ttf);
1921     post_delete(ttf);
1922     name_delete(ttf);
1923     free(ttf);
1924 }
1925
1926 #ifdef MAIN
1927 int main(int argn, const char*argv[])
1928 {
1929     setConsoleLogging(7);
1930     const char*filename = "comic.ttf";
1931     if(argn>1) 
1932         filename = argv[1];
1933     //msg("<notice> Loading %s", filename);
1934     memfile_t*m = memfile_open(filename);
1935     ttf_t*ttf = ttf_load(m->data, m->len);
1936     if(!ttf) {
1937         msg("<error> Couldn't load %s", filename);
1938         return 1;
1939     }
1940     ttf_reduce(ttf);
1941     ttf->name = strdup("testfont");
1942     if(!ttf) return 1;
1943     memfile_close(m);
1944     //ttf_dump(ttf);
1945     //printf("os2 version: %04x (%d), maxp size: %d\n", 
1946 //          ttf->os2->version, ttf->os2->size, ttf->maxp->size);
1947     ttf_save(ttf, "testfont.ttf");
1948     ttf_destroy(ttf);
1949     return 0;
1950
1951 }
1952 #endif