fix crashes reported by Debian Cylab Mayhem Team
[swftools.git] / lib / ttf.c
blob0e22cb08fa42f301a5503ca6152bbcbf86a0e21a
1 /* ttf.c
2 Parser and writer for truetype font files.
4 Part of the swftools package.
6 Copyright (c) 2010 Matthias Kramm <kramm@quiss.org>
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.
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.
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 */
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"
32 #define TTCFTAG 0x74746366
34 #define OPENTYPE 0x4f54544f
35 #define TRUETYPE_MACOS 0x74727565
36 #define VERSION_1_0 0x00010000
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
58 static U32 checksum_block(U8*_data, int len)
60 U32 sum = 0;
61 U8*data = (U8*)_data;
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];
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;
75 typedef struct _memreader {
76 U8*mem;
77 int pos;
78 int size;
79 } memreader_t;
81 static U8 readU8(memreader_t*r)
83 return r->mem[r->pos++];
85 static inline U16 readU16(memreader_t*r)
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;
93 static S16 readS16(memreader_t*r)
95 return (S16)readU16(r);
97 static U32 readU32(memreader_t*r)
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;
107 static void readBlock(memreader_t*r, void*dest, int len)
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;
119 static void reader_reset(memreader_t*r)
121 r->pos;
123 #define INIT_READ(r,data,length,pos) memreader_t r = {(data),(pos),(length)};
125 static void expand(ttf_table_t*w, int newsize)
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);
132 static inline void writeU8(ttf_table_t*w, unsigned char b)
134 if(w->memsize<w->len+1)
135 expand(w, w->len+1);
136 w->data[w->len++] = b;
138 static inline void writeU16(ttf_table_t*w, unsigned short v)
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;
145 static inline void writeU16_LE(ttf_table_t*w, unsigned short v)
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;
152 #define writeS16 writeU16
153 static inline void writeU32(ttf_table_t*w, unsigned long v)
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;
162 static inline void writeU32_LE(ttf_table_t*w, unsigned long v)
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;
171 static inline void writeBlock(ttf_table_t*w, void*data, int len)
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;
179 ttf_table_t*ttf_table_new(U32 id)
181 ttf_table_t*t = rfx_calloc(sizeof(ttf_table_t));
182 t->id = id;
183 return t;
186 ttf_table_t*ttf_addtable(ttf_t*ttf, U32 id)
188 ttf_table_t*t = ttf_table_new(id);
190 ttf_table_t*before,*after=0;
191 for(before=ttf->tables; before&&before->id<id; before=before->next) {
192 after=before;
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;
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;
210 if(t->next)
211 t->next->prev = t;
212 return t;
214 ttf_table_t*ttf_find_table(ttf_t*ttf, U32 id)
216 ttf_table_t*table = ttf->tables;
217 while(table) {
218 if(table->id == id)
219 return table;
220 table = table->next;
222 return 0;
224 void ttf_table_delete(ttf_t*ttf, ttf_table_t*table)
226 if(ttf && ttf->tables == table) {
227 ttf->tables = table->next;
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);
236 U32 ttf_table_checksum(ttf_table_t*t)
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;
245 return checksum;
247 static U8 printable(U8 a)
249 if(a<32 || a==127) return '.';
250 else return a;
252 static void hexdump(U8*data, int len, const char*prefix)
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))
262 int s,p=((t)&15)+1;
263 ascii[p] = 0;
264 for(s=p-1;s<16;s++) {
265 printf(" ");
267 if(t==len-1)
268 printf(" %s\n", ascii);
269 else
270 printf(" %s\n%s -=> ",ascii,prefix);
274 static void ttf_table_dump(ttf_table_t*t, const char*prefix)
276 if(!t) return;
277 hexdump(t->data, t->len, prefix);
280 static table_head_t*head_new(ttf_t*ttf)
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;
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;
302 static int head_parse(ttf_t*ttf, memreader_t*r)
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);
333 return loc_index;
335 static void head_write(ttf_t*ttf, ttf_table_t*w, int loca_size)
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
355 static void head_dump(ttf_t*ttf)
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);
367 static void head_delete(ttf_t*ttf)
369 if(ttf->head) {
370 free(ttf->head);
371 ttf->head=0;
375 static table_os2_t*os2_new(ttf_t*ttf)
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);
384 os2->xAvgCharWidth = average_width / ttf->num_glyphs;
387 /* that's what everybody seems to fill in */
388 os2->usWeightClass = 400;
389 os2->usWidthClass = 5;
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;
411 os2->panose_Weight = 4;
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;
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;
433 os2->sTypoAscender = ttf->ascent;
434 os2->sTypoDescender = ttf->descent;
435 os2->sTypoLineGap = ttf->lineGap;
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;
442 static table_os2_t*os2_parse(memreader_t*r)
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);
500 if(r->pos < r->size) {
501 msg("<warning> Leftover bytes (%d) in OS2 tag", r->size - r->pos);
503 return os2;
505 static void os2_write(ttf_t*ttf, ttf_table_t*w)
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;
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);
561 static void os2_dump(ttf_t*ttf)
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);
609 static void os2_delete(ttf_t*ttf)
611 if(ttf->os2)
612 free(ttf->os2);
613 ttf->os2=0;
616 static table_maxp_t*maxp_new(ttf_t*ttf)
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++;
632 if(maxp->maxContours < contours)
633 maxp->maxContours = contours;
635 maxp->maxPoints = max;
637 /* we don't generate composite glyphs yet */
638 maxp->maxComponentPoints = 0;
639 maxp->maxComponentContours = 0;
641 maxp->maxZones = 2; // we don't use the Z0 zone
642 return maxp;
644 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
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;
653 if(r->size<32)
654 msg("<warning> Truncated maxp table (version %d)", version);
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;
672 static void maxp_write(ttf_t*ttf, ttf_table_t*w)
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;
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);
697 static void maxp_dump(ttf_t*ttf)
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);
715 static void maxp_delete(ttf_t*ttf)
717 if(ttf->maxp)
718 free(ttf->maxp);
719 ttf->maxp=0;
722 static table_hea_t*hea_new(ttf_t*ttf)
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;
738 hea->caretSlopeRise = 1;
740 return hea;
742 static int hea_parse(memreader_t*r, ttf_t*ttf)
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);
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;
769 return num_advances;
771 static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances)
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;
793 static void hea_dump(ttf_t*ttf)
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);
809 static void hea_delete(ttf_t*ttf)
811 if(ttf->hea) {
812 free(ttf->hea);
813 ttf->hea=0;
817 static void mtx_parse(memreader_t*r, ttf_t*ttf, int num_advances)
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);
827 int rest = (r->size - num_advances*4)/2;
828 if(ttf->num_glyphs < num_advances+rest) {
829 rest = ttf->num_glyphs-num_advances;
831 for(t=0;t<rest;t++) {
832 ttf->glyphs[t].advance = old_advance;
833 ttf->glyphs[t].bearing = readS16(r);
836 static int mtx_write(ttf_t*ttf, ttf_table_t*w)
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;
845 /* we need to store all individual advances as well
846 as one entry for the constant */
847 num_advances = t+1;
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);
855 for(;t<ttf->num_glyphs;t++) {
856 writeS16(w, ttf->glyphs[t].bearing);
858 return num_advances;
861 static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size)
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;
874 if(num*4 < r->size) {
875 msg("<warning> Extraneous data (%d bytes) in 'loca' table (32 bit)", r->size-num*4);
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;
883 lastloc = loc;
885 } else {
886 if(num*2 > r->size) {
887 msg("<warning> Short 'loca' table (16 bit)");
888 num=r->size/2;
890 if(num*2 < r->size) {
891 msg("<warning> Extraneous data (%d bytes) in 'loca' table (16 bit)", r->size-num*2);
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;
899 lastloc = loc;
902 return locations;
904 static int loca_write(ttf_t*ttf, ttf_table_t*w, U32*locations)
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;
915 if(use_32bit) {
916 for(t=0;t<=ttf->num_glyphs;t++) {
917 writeU32(w, locations[t]);
919 return 1;
920 } else {
921 for(t=0;t<=ttf->num_glyphs;t++) {
922 writeU16(w, locations[t]/2);
924 return 0;
928 static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int glyphnr)
930 ttfglyph_t*glyph = &ttf->glyphs[glyphnr];
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);
942 lastpos = pos;
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;
952 if(!endpoints)
953 return 1;
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);
961 glyph->num_points = endpoints[num_contours-1] + 1;
962 glyph->points = rfx_calloc(sizeof(ttfpoint_t)*glyph->num_points);
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;
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;
982 num+=count;
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;
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);
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);
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);
1031 free(endpoints);
1032 return 1;
1034 static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
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;
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);
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;
1064 void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
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);
1073 /* bytecode */
1074 writeU16(w, g->code_size);
1075 if(g->code_size)
1076 writeBlock(w, g->code, g->code_size);
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;
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;
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);
1113 lastflag = flags;
1114 flagcount = 0;
1116 lastx = p->x;
1117 lasty = p->y;
1119 if(lastflag>=0) {
1120 if(flagcount) {
1121 writeU8(w, lastflag|8);
1122 writeU8(w, flagcount);
1123 } else {
1124 writeU8(w, lastflag);
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");
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);
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");
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);
1155 U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
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++;
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);
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);
1186 locations[t] = w->len;
1187 return locations;
1189 void glyf_dump(ttf_t* ttf)
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);
1205 printf(")\n");
1206 if(g->code_size)
1207 hexdump(g->code, g->code_size, " ");
1210 void glyf_delete(ttf_t* ttf)
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;
1220 if(ttf->glyphs[t].points) {
1221 free(ttf->glyphs[t].points);
1222 ttf->glyphs[t].points = 0;
1225 free(ttf->glyphs);ttf->glyphs=0;
1228 static void grow_unicode(ttf_t*ttf, int index)
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));
1237 ttf->unicode_size = size;
1239 void cmap_parse(memreader_t*r, ttf_t*ttf)
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;
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;
1259 int is_unicode = platform==0 ||
1260 platform==3 && encoding == 1 ||
1261 platform==3 && encoding == 10;
1263 if(!is_unicode)
1264 continue;
1266 INIT_READ(t, r->mem, r->size, offset);
1267 U16 format = readU16(&t);
1268 int length = readU16(&t);
1269 U16 language = readU16(&t);
1271 if(language)
1272 msg("<warning> Language code %02x in unicode mapping", language);
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;
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);
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;
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.
1316 continue;
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;
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;
1330 INIT_READ(g, t.mem, t.size, pos);
1331 for(u=start;u<=end;u++) {
1332 ttf->unicode[u] = readU16(&g);
1339 static int segment_size(unicode_t*unicode, int pos, int size)
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;
1353 s -= count; // go to the last filled in entry
1354 if(s==size)
1355 return size-1;
1356 return s;
1358 void cmap_write(ttf_t* ttf, ttf_table_t*w)
1360 writeU16(w, 0); //version
1361 writeU16(w, 2); //two tables
1363 writeU16(w, 0); //platform (unicode)
1364 writeU16(w, 3); //encoding (unicode 2.0)
1365 writeU32(w, 20); //offset
1367 writeU16(w, 3); //platform (windows)
1368 writeU16(w, 1); //encoding (unicode basic multilingual plane UCS-2)
1369 writeU32(w, 20); //offset
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
1381 int pos=0;
1382 int num_segments=0;
1383 while(pos < ttf->unicode_size) {
1384 if(!ttf->unicode[pos]) {
1385 pos++;
1386 continue;
1388 int s = segment_size(ttf->unicode, pos, ttf->unicode_size);
1389 pos = s+1;
1390 num_segments++;
1393 num_segments++; // account for 0xffff mapping
1395 int glyphmap_start = w->len+2+num_segments*8;
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
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);
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;
1431 pos=0;
1432 num_segments = 0;
1433 while(pos < ttf->unicode_size) {
1434 if(!ttf->unicode[pos]) {
1435 pos++;
1436 continue;
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;
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]);
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;
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;
1482 w->data[length_pos]=(w->len-20)>>8;
1483 w->data[length_pos+1]=w->len-20;
1485 void cmap_delete(ttf_t*ttf)
1487 if(ttf->unicode) {
1488 free(ttf->unicode);
1489 ttf->unicode=0;
1491 ttf->unicode_size=0;
1493 static char*readString(memreader_t*r, int len)
1495 char*s = malloc(len+1);
1496 readBlock(r, s, len);
1497 s[len] = 0;
1498 return s;
1500 void name_parse(memreader_t*r, ttf_t*ttf)
1502 U16 format = readU16(r);
1503 U16 count = readU16(r);
1504 U16 offset = readU16(r);
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);
1515 char ** read_name = 0;
1517 INIT_READ(ss, r->mem, r->size, offset+offset_2);
1518 if(!(platform==0 || (platform==1 && encoding==0)))
1519 continue;
1521 INIT_READ(s, r->mem, r->size, offset+offset_2);
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;
1533 if (read_name) {
1534 if (*read_name) free(*read_name);
1535 *read_name = readString(&s, len);
1539 void name_write(ttf_t*ttf, ttf_table_t*table)
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};
1544 writeU16(table, 0); //format
1545 int count = 0;
1546 int t;
1547 int nr = sizeof(strings)/sizeof(strings[0]);
1549 for(t=0;t<nr;t++) {
1550 if(strings[t])
1551 count+=2;
1553 writeU16(table, count); //count
1555 int offset_pos = table->len;
1556 writeU16(table, 0); //offset (will be filled in later)
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;
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;
1585 table->data[offset_pos] = table->len>>8;
1586 table->data[offset_pos+1] = table->len;
1588 for(t=0;t<nr;t++) {
1589 if(strings[t]) {
1590 int len = strlen(strings[t]);
1591 writeBlock(table, strings[t], len);
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]);
1605 void name_delete(ttf_t*ttf)
1607 if(ttf->full_name) {
1608 free(ttf->full_name);
1609 ttf->full_name=0;
1611 if(ttf->family_name) {
1612 free(ttf->family_name);
1613 ttf->family_name=0;
1615 if(ttf->subfamily_name) {
1616 free(ttf->subfamily_name);
1617 ttf->subfamily_name=0;
1619 if(ttf->version_string) {
1620 free(ttf->version_string);
1621 ttf->version_string=0;
1623 if(ttf->font_uid) {
1624 free(ttf->font_uid);
1625 ttf->font_uid=0;
1627 if(ttf->postscript_name) {
1628 free(ttf->postscript_name);
1629 ttf->postscript_name=0;
1633 static table_post_t*post_new(ttf_t*ttf)
1635 table_post_t*post = rfx_calloc(sizeof(table_post_t));
1636 return post;
1638 void post_parse(memreader_t*r, ttf_t*ttf)
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);
1651 void post_write(ttf_t*ttf, ttf_table_t*table)
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);
1664 void post_delete(ttf_t*ttf)
1666 if(ttf->post) {
1667 free(ttf->post);
1668 ttf->post = 0;
1672 void cvt_parse(memreader_t*r, ttf_t*ttf)
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);
1682 void cvt_write(ttf_t*ttf, ttf_table_t*table)
1684 table_cvt_t*cvt = ttf->cvt;
1685 int t;
1686 for(t=0;t<cvt->num;t++) {
1687 writeS16(table, cvt->values[t]);
1690 void cvt_delete(ttf_t*ttf)
1692 if(ttf->cvt) {
1693 if(ttf->cvt->values)
1694 free(ttf->cvt->values);
1695 free(ttf->cvt);
1696 ttf->cvt = 0;
1700 static table_gasp_t*gasp_new(ttf_t*ttf)
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);
1706 gasp->records[0].size = 65535;
1707 gasp->records[0].behaviour = 15; //gridfit+grayscale rendering
1708 return gasp;
1710 void gasp_parse(memreader_t*r, ttf_t*ttf)
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);
1724 #define GASP_SYMMETRIC_GRIDFIT 0x0008
1725 #define GASP_SYMMETRIC_SMOOTHING 0x0004
1726 #define GASP_DOGRAY 0x0002
1727 #define GASP_GRIDFIT 0x0001
1729 void gasp_write(ttf_t*ttf, ttf_table_t*table)
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;
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);
1746 void gasp_delete(ttf_t*ttf)
1748 if(ttf->gasp) {
1749 if(ttf->gasp->records)
1750 free(ttf->gasp->records);
1751 free(ttf->gasp);
1752 ttf->gasp = 0;
1756 table_code_t*prep_new(ttf_t*ttf)
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;
1772 void fpgm_parse(memreader_t*r, ttf_t*ttf)
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);
1780 void fpgm_write(ttf_t*ttf, ttf_table_t*table)
1782 table_code_t*code = ttf->fpgm;
1783 writeBlock(table, code->code, code->size);
1785 void fpgm_delete(ttf_t*ttf)
1787 if(ttf->fpgm) {
1788 if(ttf->fpgm->code)
1789 free(ttf->fpgm->code);
1790 free(ttf->fpgm);
1791 ttf->fpgm = 0;
1795 void prep_parse(memreader_t*r, ttf_t*ttf)
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);
1803 void prep_write(ttf_t*ttf, ttf_table_t*table)
1805 table_code_t*code = ttf->prep;
1806 writeBlock(table, code->code, code->size);
1808 void prep_delete(ttf_t*ttf)
1810 if(ttf->prep) {
1811 if(ttf->prep->code)
1812 free(ttf->prep->code);
1813 free(ttf->prep);
1814 ttf->prep = 0;
1818 static int ttf_parse_tables(ttf_t*ttf)
1820 ttf_table_t*table;
1822 table = ttf_find_table(ttf, TAG_HEAD);
1823 if(!table) {
1824 msg("<error> Font has no head table");
1825 return 0;
1827 INIT_READ(m, table->data, table->len, 0);
1828 int loc_index = head_parse(ttf, &m);
1829 ttf_table_delete(ttf, table);
1831 table = ttf_find_table(ttf, TAG_MAXP);
1832 if(!table) {
1833 msg("<error> Font has no maxp table");
1834 return 0;
1836 INIT_READ(m2, table->data, table->len, 0);
1837 ttf->maxp = maxp_parse(ttf, &m2);
1838 ttf_table_delete(ttf, table);
1840 if(!ttf->num_glyphs) {
1841 msg("<error> Invalid number of characters");
1842 return 0;
1844 ttf->glyphs = rfx_calloc(sizeof(ttfglyph_t)*ttf->num_glyphs);
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);
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);
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);
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);
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);
1880 } else {
1881 msg("<error> Font contains neither HHEA nor VHEA");
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);
1895 free(loca);
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);
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);
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);
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);
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);
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);
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);
1947 return 1;
1949 static void ttf_collapse_tables(ttf_t*ttf)
1951 ttf_table_t*table;
1953 ttf_table_t*head = ttf_find_table(ttf, TAG_HEAD);
1954 if(head)
1955 return; //already collapsed
1957 if(ttf->maxp) {
1958 table = ttf_addtable(ttf, TAG_MAXP);
1959 maxp_write(ttf, table);
1960 maxp_delete(ttf);
1963 if(ttf->os2) {
1964 table = ttf_addtable(ttf, TAG_OS2);
1965 os2_write(ttf, table);
1966 os2_delete(ttf);
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);
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);
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);
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);
2008 if(ttf->post) {
2009 table = ttf_addtable(ttf, TAG_POST);
2010 post_write(ttf, table);
2011 post_delete(ttf);
2013 if(ttf->cvt) {
2014 table = ttf_addtable(ttf, TAG_CVT);
2015 cvt_write(ttf, table);
2016 cvt_delete(ttf);
2018 if(ttf->gasp) {
2019 table = ttf_addtable(ttf, TAG_GASP);
2020 gasp_write(ttf, table);
2021 gasp_delete(ttf);
2023 if(ttf->fpgm) {
2024 table = ttf_addtable(ttf, TAG_FPGM);
2025 fpgm_write(ttf, table);
2026 fpgm_delete(ttf);
2028 if(ttf->prep) {
2029 table = ttf_addtable(ttf, TAG_PREP);
2030 prep_write(ttf, table);
2031 prep_delete(ttf);
2034 table = ttf_addtable(ttf, TAG_HEAD);
2035 head_write(ttf, table, loca_size);
2036 head_delete(ttf);
2039 ttf_t*ttf_new()
2041 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
2042 ttf->version = VERSION_1_0;
2043 return ttf;
2045 ttf_t* ttf_load(void*data, int length)
2047 INIT_READ(r,data,length, 0);
2049 if(length<12) {
2050 msg("<error> Truncated Truetype file (%d bytes)", length);
2051 return 0;
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
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;
2095 readU16(&r); // zero terminator
2097 readU16(&r); // more padding
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);
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;
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;
2126 r.pos = font1_position;
2127 ttf->version = readU32(&r);
2130 int num_tables = readU16(&r);
2132 readU16(&r); //search range
2133 readU16(&r); //entry selector
2134 readU16(&r); //range shift
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;
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);
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];
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);
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);
2175 #endif
2178 free(table_data);
2180 if(!ttf_parse_tables(ttf))
2181 return 0;
2183 return ttf;
2185 void ttf_create_truetype_tables(ttf_t*ttf)
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);
2203 ttf_table_t* ttf_write(ttf_t*ttf, U32*checksum_adjust)
2205 ttf_collapse_tables(ttf);
2207 ttf_table_t*file = ttf_table_new(0);
2208 writeU32(file, VERSION_1_0);
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;
2217 writeU16(file, num_tables);
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);
2226 tmp = search_range;
2227 search_range*=16;
2228 writeU16(file, search_range);
2230 /* write entry selector */
2231 int entry_selector = 0;
2232 while(tmp>1) {
2233 tmp>>=1;
2234 entry_selector++;
2236 writeU16(file, entry_selector);
2238 /* write range shift */
2239 int range_shift = num_tables*16 - search_range;
2240 writeU16(file, range_shift);
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
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
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;
2274 ttf_table_t* ttf_eot_head(ttf_t*ttf)
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)
2309 int i,t,len;
2311 char* strings[] = {ttf->family_name, ttf->subfamily_name, ttf->version_string, ttf->full_name};
2312 int nr = sizeof(strings)/sizeof(strings[0]);
2314 for(i=0;i<nr;i++) {
2315 char *string = strings[i];
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]);
2324 writeU16(file, 0); //zero byte pad
2327 writeU16(file, 0); //zero byte pad
2329 writeU16(file, 0); //padding(2)
2330 return file;
2333 void ttf_save_eot(ttf_t*ttf, const char*filename)
2335 ttf_table_t* eot = ttf_eot_head(ttf);
2336 U32 checksum_adjust = 0;
2337 ttf_table_t* t = ttf_write(ttf, &checksum_adjust);
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;
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;
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;
2358 FILE*fi = fopen(filename, "wb");
2359 if(!fi) {
2360 perror(filename);
2361 return;
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);
2371 void ttf_save(ttf_t*ttf, const char*filename)
2373 ttf_table_t* t = ttf_write(ttf, 0);
2374 FILE*fi = fopen(filename, "wb");
2375 if(!fi) {
2376 perror(filename);
2377 return;
2379 fwrite(t->data, t->len, 1, fi);
2380 fclose(fi);
2381 ttf_table_delete(0, t);
2384 void ttf_dump(ttf_t*ttf)
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;
2395 //ttf_table_dump(ttf_find_table(ttf, TAG_MAXP));
2397 head_dump(ttf);
2398 hea_dump(ttf);
2399 os2_dump(ttf);
2400 maxp_dump(ttf);
2401 glyf_dump(ttf);
2403 void ttf_destroy_tables(ttf_t*ttf)
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;
2412 ttf->tables = 0;
2414 void ttf_reduce(ttf_t*ttf)
2416 ttf_destroy_tables(ttf);
2418 void ttf_destroy(ttf_t*ttf)
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);
2432 ttf_t* ttf_open(const char*filename)
2434 memfile_t*m = memfile_open(filename);
2435 ttf_t*ttf = ttf_load(m->data, m->len);
2436 memfile_close(m);
2437 return ttf;
2440 #ifdef MAIN
2441 int main(int argn, const char*argv[])
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);
2451 if(!ttf) {
2452 msg("<error> Couldn't load %s", filename);
2453 return 1;
2455 ttf_reduce(ttf);
2457 ttf_create_truetype_tables(ttf);
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;
2470 #endif