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