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