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