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