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 */
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)
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];
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;
75 typedef struct _memreader {
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|
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|
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);
115 memcpy(dest, r->mem+r->pos, len);
119 static void reader_reset(memreader_t*r)
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)
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)
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)
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)
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)
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);
179 ttf_table_t*ttf_table_new(U32 id)
181 ttf_table_t*t = rfx_calloc(sizeof(ttf_table_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) {
194 if(before && before->id == id) {
195 msg("<error> Error: duplicate table %08x", id);
203 t->next = ttf->tables;
207 t->next = after->next;
214 ttf_table_t*ttf_find_table(ttf_t*ttf, U32 id)
216 ttf_table_t*table = ttf->tables;
224 void ttf_table_delete(ttf_t*ttf, ttf_table_t*table)
226 if(ttf && ttf->tables == table) {
227 ttf->tables = table->next;
230 table->prev->next = table->next;
232 table->next->prev = table->prev;
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];
247 static U8 printable(U8 a)
249 if(a<32 || a==127) return '.';
252 static void hexdump(U8*data, int len, const char*prefix)
256 printf("%s -=> ",prefix);
258 printf("%02x ", data[t]);
259 ascii[t&15] = printable(data[t]);
260 if((t && ((t&15)==15)) || (t==len-1))
264 for(s=p-1;s<16;s++) {
268 printf(" %s\n", ascii);
270 printf(" %s\n%s -=> ",ascii,prefix);
274 static void ttf_table_dump(ttf_table_t*t, const char*prefix)
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;
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;
298 head->lowest_readable_size = 8; // not sure what font renderers actually do with this
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
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);
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)
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) {
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;
392 int advance = (ttf->head->xmax - ttf->head->xmin)/2;
393 int height = (ttf->head->xmax - ttf->head->xmin);
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;
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) {
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;
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
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);
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);
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);
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);
505 static void os2_write(ttf_t*ttf, ttf_table_t*w)
507 table_os2_t*os2 = ttf->os2;
509 if(os2->sxHeight|os2->sCapHeight|os2->usDefaultChar|os2->usBreakChar|os2->usMaxContext) {
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;
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)
616 static table_maxp_t*maxp_new(ttf_t*ttf)
618 table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
621 if(ttf->num_glyphs) {
623 for(t=0;t<ttf->num_glyphs;t++) {
624 if(ttf->glyphs[t].num_points>max)
625 max = ttf->glyphs[t].num_points;
628 for(s=0;s<ttf->glyphs[t].num_points;s++) {
629 if(ttf->glyphs[t].points[s].flags&GLYPH_CONTOUR_END)
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;
643 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
645 U32 version = readU32(r);
646 ttf->num_glyphs = readU16(r);
647 /* according to freetype, older fonts (version<0x10000)
648 apparently only contain the number of glyphs. this is
649 rather rare, though. */
650 if(version<0x10000 && r->size==6) return 0;
653 msg("<warning> Truncated maxp table (version %d)", version);
655 table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
656 maxp->maxPoints = readU16(r);
657 maxp->maxContours = readU16(r);
658 maxp->maxComponentPoints = readU16(r);
659 maxp->maxComponentContours = readU16(r);
660 maxp->maxZones = readU16(r);
661 maxp->maxTwilightPoints = readU16(r);
662 maxp->maxStorage = readU16(r);
663 maxp->maxFunctionDefs = readU16(r);
664 maxp->maxInstructionDefs = readU16(r);
665 maxp->maxStackElements = readU16(r);
666 maxp->maxSizeOfInstructions = readU16(r);
667 maxp->maxComponentElements = readU16(r);
668 maxp->maxComponentDepth = readU16(r);
671 static void maxp_write(ttf_t*ttf, ttf_table_t*w)
673 table_maxp_t*maxp = ttf->maxp;
675 /* version 0.5 simplified maxp table */
676 writeU32(w, 0x00005000);
677 writeU16(w, ttf->num_glyphs);
680 writeU32(w, 0x10000); //version
681 writeU16(w, ttf->num_glyphs);
682 writeU16(w, maxp->maxPoints);
683 writeU16(w, maxp->maxContours);
684 writeU16(w, maxp->maxComponentPoints);
685 writeU16(w, maxp->maxComponentContours);
686 writeU16(w, maxp->maxZones);
687 writeU16(w, maxp->maxTwilightPoints);
688 writeU16(w, maxp->maxStorage);
689 writeU16(w, maxp->maxFunctionDefs);
690 writeU16(w, maxp->maxInstructionDefs);
691 writeU16(w, maxp->maxStackElements);
692 writeU16(w, maxp->maxSizeOfInstructions);
693 writeU16(w, maxp->maxComponentElements);
694 writeU16(w, maxp->maxComponentDepth);
696 static void maxp_dump(ttf_t*ttf)
698 table_maxp_t*maxp = ttf->maxp;
700 printf("maxp->maxPoints: %d\n", maxp->maxPoints);
701 printf("maxp->maxContours: %d\n", maxp->maxContours);
702 printf("maxp->maxComponentPoints: %d\n", maxp->maxComponentPoints);
703 printf("maxp->maxComponentContours: %d\n", maxp->maxComponentContours);
704 printf("maxp->maxZones: %d\n", maxp->maxZones);
705 printf("maxp->maxTwilightPoints: %d\n", maxp->maxTwilightPoints);
706 printf("maxp->maxStorage: %d\n", maxp->maxStorage);
707 printf("maxp->maxFunctionDefs: %d\n", maxp->maxFunctionDefs);
708 printf("maxp->maxInstructionDefs: %d\n", maxp->maxInstructionDefs);
709 printf("maxp->maxStackElements: %d\n", maxp->maxStackElements);
710 printf("maxp->maxSizeOfInstructions: %d\n", maxp->maxSizeOfInstructions);
711 printf("maxp->maxComponentElements: %d\n", maxp->maxComponentElements);
712 printf("maxp->maxComponentDepth: %d\n", maxp->maxComponentDepth);
714 static void maxp_delete(ttf_t*ttf)
721 static table_hea_t*hea_new(ttf_t*ttf)
723 table_hea_t*hea = rfx_calloc(sizeof(table_hea_t));
724 if(ttf->num_glyphs) {
726 for(t=0;t<ttf->num_glyphs;t++) {
727 if(ttf->glyphs[t].advance > hea->advanceWidthMax)
728 hea->advanceWidthMax = ttf->glyphs[t].advance;
729 if(ttf->glyphs[t].xmin < hea->minLeftSideBearing)
730 hea->minLeftSideBearing = ttf->glyphs[t].xmin;
731 if(ttf->glyphs[t].xmax < hea->minRightSideBearing)
732 hea->minRightSideBearing = ttf->glyphs[t].xmax;
733 int width = ttf->glyphs[t].xmax - ttf->glyphs[t].xmin;
734 if(width > hea->xMaxExtent)
735 hea->xMaxExtent = width;
737 hea->caretSlopeRise = 1;
741 static int hea_parse(memreader_t*r, ttf_t*ttf)
743 table_hea_t*hea = ttf->hea = rfx_calloc(sizeof(table_hea_t));
744 U32 version = readU32(r);
745 ttf->ascent = readS16(r);
746 ttf->descent = readS16(r);
747 ttf->lineGap = readS16(r);
748 hea->advanceWidthMax = readU16(r);
749 hea->minLeftSideBearing = readS16(r);
750 hea->minRightSideBearing = readS16(r);
751 hea->xMaxExtent = readS16(r);
752 hea->caretSlopeRise = readS16(r);
753 hea->caretSlopeRun = readS16(r);
754 hea->caretOffset = readS16(r);
755 readS16(r); //reserved[0]
756 readS16(r); //reserved[1]
757 readS16(r); //reserved[2]
758 readS16(r); //reserved[3]
759 S16 metricDataFormat = readS16(r); //should be 0
760 if(metricDataFormat!=0) {
761 msg("<warning> Unknown metric format %d", metricDataFormat);
763 int num_advances = readU16(r);
764 if(num_advances > ttf->num_glyphs) {
765 msg("<warning> bad number of horizontal metrics: %d", num_advances);
766 num_advances = ttf->num_glyphs;
770 static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances)
772 table_hea_t*hea = ttf->hea;
773 writeU32(w, 0x00010000);
774 writeS16(w, ttf->ascent);
775 writeS16(w, ttf->descent);
776 writeS16(w, ttf->lineGap);
777 writeU16(w, hea->advanceWidthMax);
778 writeS16(w, hea->minLeftSideBearing);
779 writeS16(w, hea->minRightSideBearing);
780 writeS16(w, hea->xMaxExtent);
781 writeS16(w, hea->caretSlopeRise);
782 writeS16(w, hea->caretSlopeRun);
783 writeS16(w, hea->caretOffset);
784 writeS16(w, 0); //reserved
785 writeS16(w, 0); //reserved
786 writeS16(w, 0); //reserved
787 writeS16(w, 0); //reserved
788 writeS16(w, 0); //metricDataFormat
789 writeU16(w, num_advances);
792 static void hea_dump(ttf_t*ttf)
794 table_hea_t*hea = ttf->hea;
796 const char*dir = ttf->is_vertical?"v":"h";
797 printf("%shea->ascent: %d\n", dir, ttf->ascent);
798 printf("%shea->descent: %d\n", dir, ttf->descent);
799 printf("%shea->lineGap: %d\n", dir, ttf->lineGap);
800 printf("%shea->advanceWidthMax: %d\n", dir, hea->advanceWidthMax);
801 printf("%shea->minLeftSideBearing: %d\n", dir, hea->minLeftSideBearing);
802 printf("%shea->minRightSideBearing: %d\n", dir, hea->minRightSideBearing);
803 printf("%shea->xMaxExtent: %d\n", dir, hea->xMaxExtent);
804 printf("%shea->caretSlopeRise: %d\n", dir, hea->caretSlopeRise);
805 printf("%shea->caretSlopeRun: %d\n", dir, hea->caretSlopeRun);
806 printf("%shea->caretOffset: %d\n", dir, hea->caretOffset);
808 static void hea_delete(ttf_t*ttf)
816 static void mtx_parse(memreader_t*r, ttf_t*ttf, int num_advances)
820 if(num_advances > r->size/4)
821 num_advances = r->size/4;
822 for(t=0;t<num_advances;t++) {
823 old_advance = ttf->glyphs[t].advance = readU16(r);
824 ttf->glyphs[t].bearing = readS16(r);
826 int rest = (r->size - num_advances*4)/2;
827 if(ttf->num_glyphs < num_advances+rest) {
828 rest = ttf->num_glyphs-num_advances;
830 for(t=0;t<rest;t++) {
831 ttf->glyphs[t].advance = old_advance;
832 ttf->glyphs[t].bearing = readS16(r);
835 static int mtx_write(ttf_t*ttf, ttf_table_t*w)
837 int num_advances = ttf->num_glyphs;
838 if(ttf->num_glyphs>=2) {
840 for(t=ttf->num_glyphs-1;t>0;t--) {
841 if(ttf->glyphs[t-1].advance !=
842 ttf->glyphs[t].advance) break;
844 /* we need to store all individual advances as well
845 as one entry for the constant */
850 for(t=0;t<num_advances;t++) {
851 writeU16(w, ttf->glyphs[t].advance);
852 writeU16(w, ttf->glyphs[t].bearing);
854 for(;t<ttf->num_glyphs;t++) {
855 writeU16(w, ttf->glyphs[t].bearing);
860 static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size)
863 int num = ttf->num_glyphs+1;
864 U32*locations = rfx_calloc(num*sizeof(U32));
867 char warn_unsorted = 1;
869 if(num*4 > r->size) {
870 msg("<warning> Short 'loca' table (32 bit): %d/%d", r->size/4, num);
873 if(num*4 < r->size) {
874 msg("<warning> Extraneous data (%d bytes) in 'loca' table (32 bit)", r->size-num*4);
877 locations[t] = loc = readU32(r);
878 if(lastloc > loc && warn_unsorted) {
879 msg("<warning> Unsorted 'loca' table (32 bit)");
885 if(num*2 > r->size) {
886 msg("<warning> Short 'loca' table (16 bit)");
889 if(num*2 < r->size) {
890 msg("<warning> Extraneous data (%d bytes) in 'loca' table (16 bit)", r->size-num*2);
893 locations[t] = loc = readU16(r)*2;
894 if(lastloc > loc && warn_unsorted) {
895 msg("<warning> Unsorted 'loca' table");
903 static int loca_write(ttf_t*ttf, ttf_table_t*w, U32*locations)
907 for(t=0;t<=ttf->num_glyphs;t++) {
908 if(locations[t]>=0x20000 || (locations[t]&1)) {
915 for(t=0;t<=ttf->num_glyphs;t++) {
916 writeU32(w, locations[t]);
920 for(t=0;t<=ttf->num_glyphs;t++) {
921 writeU16(w, locations[t]/2);
927 static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int glyphnr)
929 ttfglyph_t*glyph = &ttf->glyphs[glyphnr];
933 endpoints = malloc(sizeof(U16)*num_contours);
936 for(s=0;s<num_contours;s++) {
937 int pos = endpoints[s] = readU16(r);
939 msg("<warning> Unsorted endpoints array (len:%d) last=%d now=%d", s, pos, lastpos);
944 U16 code_len = readU16(r);
946 glyph->code = malloc(sizeof(U16)*code_len);
947 readBlock(r, glyph->code, code_len);
948 glyph->code_size = code_len;
954 /*msg("<notice> TTF Glyph %d) code_size=%d num_contours=%d glyph->num_points=%d %d/%d/%d/%d",
955 glyphnr, code_len, num_contours, glyph->num_points,
956 xmin, ymin, xmax, ymax);*/
957 INIT_READ(fx, r->mem, r->size, r->pos);
958 INIT_READ(fy, r->mem, r->size, r->pos);
960 glyph->num_points = endpoints[num_contours-1] + 1;
961 glyph->points = rfx_calloc(sizeof(ttfpoint_t)*glyph->num_points);
963 /* parse flag array (1st pass- to determine start of coordinates) */
965 while(num<glyph->num_points) {
968 msg("<error> Bad flags in glyph outline: %02x (at pos %d)", flag, num);
971 glyph->num_points = 0;
977 if(count+num>glyph->num_points) {
978 msg("<warning> Bad count (%d) in glyph (%d) (at pos %d)", count, glyphnr, num);
979 count = glyph->num_points-num;
984 /* parse flag array (2nd pass) and x coordinates */
989 int bytepos = r->pos;
990 while(num<glyph->num_points) {
991 U8 flag = readU8(&fx);
992 int count = flag&8?readU8(&fx)+1:1;
993 count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
996 if(contour_pos<num_contours && num==endpoints[contour_pos]) {
1001 if((flag&0x12) == 0x12) x += readU8(r);
1002 else if((flag&0x12) == 0x02) x -= readU8(r);
1003 else if((flag&0x12) == 0x00) x += readS16(r);
1005 glyph->points[num].x = x;
1006 U8 f = flag&GLYPH_ON_CURVE;
1007 if(is_start) f|=GLYPH_CONTOUR_START;
1008 if(is_end) f|=GLYPH_CONTOUR_END;
1009 glyph->points[num].flags = f;
1015 /* parse flag array (3rd pass) and y coordinates */
1018 while(num<glyph->num_points) {
1019 U8 flag = readU8(&fy);
1020 int count = flag&8?readU8(&fy)+1:1;
1021 count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
1023 if((flag&0x24) == 0x24) y += readU8(r);
1024 else if((flag&0x24) == 0x04) y -= readU8(r);
1025 else if((flag&0x24) == 0x00) y += readS16(r);
1026 glyph->points[num].y = y;
1033 static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
1036 char warn_about_compound_glyphs=0;
1037 for(t=0;t<ttf->num_glyphs;t++) {
1038 INIT_READ(r, rr->mem, rr->size, loca[t]);
1039 if(loca[t]==loca[t+1] || loca[t]==r.size)
1040 continue; //empty glyph
1041 if(r.pos+10>r.size) {
1042 msg("<warning> Truncated glyph entry %d/%d (or bad loca entry %d/%d, next loca: %d)",
1043 t, ttf->num_glyphs, loca[t], r.size, loca[t+1]);
1046 S16 num_contours = readS16(&r);
1047 ttf->glyphs[t].xmin = readS16(&r);
1048 ttf->glyphs[t].ymin = readS16(&r);
1049 ttf->glyphs[t].xmax = readS16(&r);
1050 ttf->glyphs[t].ymax = readS16(&r);
1052 if(num_contours<0) {
1053 if(warn_about_compound_glyphs)
1054 msg("<error> Compound glyphs not supported yet");
1055 warn_about_compound_glyphs=0;
1057 if(!parse_simple_glyph(ttf, &r, num_contours, t))
1063 void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
1065 /* endpoints array */
1067 for(s=0;s<g->num_points;s++) {
1068 if(g->points[s].flags&GLYPH_CONTOUR_END)
1073 writeU16(w, g->code_size);
1075 writeBlock(w, g->code, g->code_size);
1082 for(s=0;s<g->num_points;s++) {
1083 ttfpoint_t*p = &g->points[s];
1084 int dx = p->x - lastx;
1085 int dy = p->y - lasty;
1086 U8 flags = p->flags&GLYPH_ON_CURVE;
1089 } else if(dx<0 && dx>=-255) {
1091 } else if(dx>0 && dx<=255) {
1096 } else if(dy<0 && dy>=-255) {
1098 } else if(dy>0 && dy<=255) {
1101 if(flags == lastflag && flagcount<255) {
1106 writeU8(w, lastflag|8);
1107 writeU8(w, flagcount);
1109 writeU8(w, lastflag);
1120 writeU8(w, lastflag|8);
1121 writeU8(w, flagcount);
1123 writeU8(w, lastflag);
1128 int bytepos = w->len;
1129 for(s=0;s<g->num_points;s++) {
1130 ttfpoint_t*p = &g->points[s];
1131 int dx = p->x - lastx;
1132 if(dx>32767 || dx<-32768) {
1133 msg("<error> Coordinate overflow in glyph");
1136 if(dx>0 && dx<=255) writeU8(w, dx);
1137 else if(dx<0 && dx>=-255) writeU8(w, -dx);
1138 else if(dx) writeS16(w, dx);
1142 for(s=0;s<g->num_points;s++) {
1143 ttfpoint_t*p = &g->points[s];
1144 int dy = p->y - lasty;
1145 if(dy>32767 || dy<-32768) {
1146 msg("<error> Coordinate overflow in glyph");
1149 if(dy>0 && dy<=255) writeU8(w, dy);
1150 else if(dy<0 && dy>=-255) writeU8(w, -dy);
1151 else if(dy) writeS16(w, dy);
1154 U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
1156 U32*locations = malloc(sizeof(U32)*(ttf->num_glyphs+1));
1158 for(t=0;t<ttf->num_glyphs;t++) {
1159 locations[t] = w->len;
1160 ttfglyph_t*g = &ttf->glyphs[t];
1162 int num_contours = 0;
1163 for(s=0;s<g->num_points;s++) {
1164 if(g->points[s].flags&GLYPH_CONTOUR_END)
1167 writeS16(w, num_contours?num_contours:1);
1168 writeS16(w, g->xmin);
1169 writeS16(w, g->ymin);
1170 writeS16(w, g->xmax);
1171 writeS16(w, g->ymax);
1174 /* some ttf parsers can't deal with zero contours, so in the case
1175 of an empty glyph, write a single point (0,0) */
1176 writeU16(w, 0); //endpoint of 1st contour
1177 writeU16(w, g->code_size);
1179 writeBlock(w, g->code, g->code_size);
1180 writeU8(w, 0x31); //flag (xy=(0,0),on curve)
1182 write_simple_glyph(w, g);
1185 locations[t] = w->len;
1188 void glyf_dump(ttf_t* ttf)
1190 if(!ttf->glyphs) return;
1192 for(t=0;t<ttf->num_glyphs;t++) {
1193 ttfglyph_t*g = &ttf->glyphs[t];
1194 printf("glyph %d)\n", t);
1195 printf(" advance=%d\n", g->advance);
1196 printf(" bearing=%d\n", g->bearing);
1197 printf(" bbox=(%d/%d/%d/%d)\n", g->xmin, g->ymin, g->xmax, g->ymax);
1198 printf(" points=(");
1200 for(s=0;s<g->num_points;s++) {
1202 printf("%d/%d/0x%02x", g->points[s].x, g->points[s].y, g->points[s].flags);
1206 hexdump(g->code, g->code_size, " ");
1209 void glyf_delete(ttf_t* ttf)
1214 for(t=0;t<ttf->num_glyphs;t++) {
1215 if(ttf->glyphs[t].code) {
1216 free(ttf->glyphs[t].code);
1217 ttf->glyphs[t].code = 0;
1219 if(ttf->glyphs[t].points) {
1220 free(ttf->glyphs[t].points);
1221 ttf->glyphs[t].points = 0;
1224 free(ttf->glyphs);ttf->glyphs=0;
1227 static void grow_unicode(ttf_t*ttf, int index)
1231 ttf->unicode = rfx_calloc(sizeof(ttf->unicode[0])*size);
1232 } else if(ttf->unicode_size<size) {
1233 ttf->unicode = rfx_realloc(ttf->unicode, sizeof(ttf->unicode[0])*size);
1234 memset(ttf->unicode+ttf->unicode_size, 0, sizeof(ttf->unicode[0])*(size - ttf->unicode_size));
1236 ttf->unicode_size = size;
1238 void cmap_parse(memreader_t*r, ttf_t*ttf)
1240 readU16(r); // version (0)
1241 int num_subtables = readU16(r);
1244 if(r->pos+num_subtables*8 > r->size) {
1245 msg("<warning> CMap overflow");
1246 num_subtables = (r->size-r->pos)/8;
1249 for(t=0;t<num_subtables;t++) {
1250 U16 platform = readU16(r);
1251 U16 encoding = readU16(r);
1252 U32 offset = readU32(r);
1253 if(offset>r->size) {
1254 msg("<warning> CMAP table %d %d is out of bounds (%d)", platform, encoding, offset);
1258 int is_unicode = platform==0 ||
1259 platform==3 && encoding == 1 ||
1260 platform==3 && encoding == 10;
1265 INIT_READ(t, r->mem, r->size, offset);
1266 U16 format = readU16(&t);
1267 int length = readU16(&t);
1268 U16 language = readU16(&t);
1271 msg("<warning> Language code %02x in unicode mapping", language);
1276 if(t.pos+length > t.size) {
1277 msg("<warning> overflow in format 0 cmap table");
1280 data = malloc(num*sizeof(unicode_t));
1282 grow_unicode(ttf, num);
1283 for(s=0;s<num;s++) {
1284 ttf->unicode[s] = readU8(&t);
1286 } else if(format == 4) {
1287 U16 segment_count = readU16(&t);
1288 if(segment_count&1) {
1289 msg("<error> Bad segmentx2 count %d", segment_count);
1293 readU16(&t); //searchrange
1294 readU16(&t); //entry selector
1295 readU16(&t); //range shift
1296 INIT_READ(r_end, t.mem, t.size, t.pos);
1297 INIT_READ(r_start, t.mem, t.size, t.pos+2+segment_count*2);
1298 INIT_READ(r_delta, t.mem, t.size, t.pos+2+segment_count*4);
1299 INIT_READ(r_range, t.mem, t.size, t.pos+2+segment_count*6);
1300 int glyphmap_start = t.pos+2+segment_count*8;
1301 int glyphmap_size = t.size - glyphmap_start;
1303 for(s=0;s<segment_count;s++) {
1304 U16 start = readU16(&r_start);
1305 U16 end = readU16(&r_end);
1306 U16 delta = readU16(&r_delta);
1307 U16 range = readU16(&r_range);
1308 if(start==0xffff && end==0xffff && delta==1) {
1309 /* this is a common (maybe even required) occurence in fonts
1310 which explicitly map "unicode undefined" (0xffff) to
1311 "glyph undefined" (0).
1312 We don't want to blow our unicode table up to 65536 just
1313 because of this, so ignore this entry.
1317 grow_unicode(ttf, end);
1320 for(u=start;u<=end;u++) {
1321 ttf->unicode[u] = (u + delta) & 0xffff;
1324 int pos = r_range.pos-2+range;
1325 if(warn && pos+end-start+1 > t.size) {
1326 msg("<warning> glyphmap index out of bounds (%d-%d/%d)", pos, pos+end-start, t.size);
1329 INIT_READ(g, t.mem, t.size, pos);
1330 for(u=start;u<=end;u++) {
1331 ttf->unicode[u] = readU16(&g);
1338 static int segment_size(unicode_t*unicode, int pos, int size)
1342 for(s=pos;s<size;s++) {
1346 /* a segment costs us 8 bytes, so for more than 4 consecutive
1347 zero entries (16 bit each) in the glyph index array,
1348 it pays off to start a new segment */
1352 s -= count; // go to the last filled in entry
1357 void cmap_write(ttf_t* ttf, ttf_table_t*w)
1359 writeU16(w, 0); //version
1360 writeU16(w, 2); //two tables
1362 writeU16(w, 0); //platform (unicode)
1363 writeU16(w, 3); //encoding (unicode 2.0)
1364 writeU32(w, 20); //offset
1366 writeU16(w, 3); //platform (windows)
1367 writeU16(w, 1); //encoding (unicode basic multilingual plane UCS-2)
1368 writeU32(w, 20); //offset
1370 writeU16(w, 4); // format=4
1371 int length_pos = w->len;
1372 writeU16(w, 0); // length: we don't know yet
1373 writeU16(w, 0); // language (n/a for unicode)
1374 int num_segments_pos = w->len;
1375 writeU16(w, 0); //number of segments: we don't know yet either
1376 writeU16(w, 0); //searchrange
1377 writeU16(w, 0); //entry selector
1378 writeU16(w, 0); //range shift
1382 while(pos < ttf->unicode_size) {
1383 if(!ttf->unicode[pos]) {
1387 int s = segment_size(ttf->unicode, pos, ttf->unicode_size);
1392 num_segments++; // account for 0xffff mapping
1394 int glyphmap_start = w->len+2+num_segments*8;
1397 int end_pos = w->len;
1398 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
1399 writeU16(w, 0); //reserved byte
1400 int start_pos = w->len;
1401 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //start array
1402 int delta_pos = w->len;
1403 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //delta array
1404 int range_pos = w->len;
1405 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //range array
1407 /* backpatch number of segments */
1408 w->data[num_segments_pos++]=(num_segments*2)>>8;
1409 w->data[num_segments_pos++]=(num_segments*2);
1410 /* backpatch search range */
1411 int tmp = num_segments;
1412 int search_range = 0;
1417 w->data[num_segments_pos++]=(search_range*2)>>8;
1418 w->data[num_segments_pos++]=(search_range*2);
1419 /* backpatch entry selector */
1420 int entry_selector = 0;
1421 while(tmp>1) {tmp>>=1;entry_selector++;}
1422 w->data[num_segments_pos++]=entry_selector>>8;
1423 w->data[num_segments_pos++]=entry_selector;
1424 /* backpatch range shift */
1425 int range_shift = num_segments*2 - search_range;
1426 w->data[num_segments_pos++]=range_shift>>8;
1427 w->data[num_segments_pos++]=range_shift;
1431 while(pos < ttf->unicode_size) {
1432 if(!ttf->unicode[pos]) {
1436 U16 end = segment_size(ttf->unicode, pos, ttf->unicode_size);
1437 w->data[end_pos++]=end>>8;
1438 w->data[end_pos++]=end;
1439 w->data[start_pos++]=pos>>8;
1440 w->data[start_pos++]=pos;
1442 U16 delta = ttf->unicode[pos]-pos;
1444 for(s=pos+1;s<=end;s++) {
1445 U16 delta2 = ttf->unicode[s]-s;
1456 range = w->len - range_pos;
1457 for(s=pos;s<=end;s++) {
1458 writeU16(w, ttf->unicode[s]);
1461 w->data[delta_pos++]=delta>>8;
1462 w->data[delta_pos++]=delta;
1463 w->data[range_pos++]=range>>8;
1464 w->data[range_pos++]=range;
1469 /* write out a mapping from 0xffff to 0- seems to be required
1470 by some libraries (e.g. fonttools) */
1471 w->data[end_pos++]=0xff;
1472 w->data[end_pos++]=0xff;
1473 w->data[start_pos++]=0xff;
1474 w->data[start_pos++]=0xff;
1475 w->data[delta_pos++]=0;
1476 w->data[delta_pos++]=1;
1477 w->data[range_pos++]=0;
1478 w->data[range_pos++]=0;
1480 w->data[length_pos]=(w->len-20)>>8;
1481 w->data[length_pos+1]=w->len-20;
1483 void cmap_delete(ttf_t*ttf)
1489 ttf->unicode_size=0;
1491 static char*readString(memreader_t*r, int len)
1493 char*s = malloc(len+1);
1494 readBlock(r, s, len);
1498 void name_parse(memreader_t*r, ttf_t*ttf)
1500 U16 format = readU16(r);
1501 U16 count = readU16(r);
1502 U16 offset = readU16(r);
1505 for(t=0;t<count;t++) {
1506 U16 platform = readU16(r);
1507 U16 encoding = readU16(r);
1508 U16 language = readU16(r);
1509 U16 name_id = readU16(r);
1510 U16 len = readU16(r);
1511 U16 offset_2 = readU16(r);
1513 char ** read_name = 0;
1515 INIT_READ(ss, r->mem, r->size, offset+offset_2);
1516 if(!(platform==0 || (platform==1 && encoding==0)))
1519 INIT_READ(s, r->mem, r->size, offset+offset_2);
1522 case 1: read_name = &ttf->family_name; break;
1523 case 2: read_name = &ttf->subfamily_name; break;
1524 case 3: read_name = &ttf->font_uid; break;
1525 case 4: read_name = &ttf->full_name; break;
1526 case 5: read_name = &ttf->version_string; break;
1527 case 6: read_name = &ttf->postscript_name; break;
1528 default: read_name = 0;
1532 if (*read_name) free(*read_name);
1533 *read_name = readString(&s, len);
1537 void name_write(ttf_t*ttf, ttf_table_t*table)
1539 char*strings[6] = {ttf->family_name, ttf->subfamily_name, ttf->font_uid, ttf->full_name, ttf->version_string, ttf->postscript_name};
1540 int codes[6] = {1,2,3,4,5,6};
1542 writeU16(table, 0); //format
1545 int nr = sizeof(strings)/sizeof(strings[0]);
1551 writeU16(table, count); //count
1553 int offset_pos = table->len;
1554 writeU16(table, 0); //offset (will be filled in later)
1556 /* Windows expects the name table to be sorted by platform/encoding/language/name_id */
1560 writeU16(table, 1); //platform id (mac)
1561 writeU16(table, 0); //encoding id (latin-1)
1562 writeU16(table, 0); //language (english)
1563 writeU16(table, codes[t]);
1564 int len = strlen(strings[t]);
1565 writeU16(table, len);
1566 writeU16(table, offset);
1572 writeU16(table, 3); //platform id (windows)
1573 writeU16(table, 1); //encoding id (ucs-2)
1574 writeU16(table, 0x409); //language (US)
1575 writeU16(table, codes[t]);
1576 int len2 = strlen(strings[t]) * 2;
1577 writeU16(table, len2);
1578 writeU16(table, offset);
1583 table->data[offset_pos] = table->len>>8;
1584 table->data[offset_pos+1] = table->len;
1588 int len = strlen(strings[t]);
1589 writeBlock(table, strings[t], len);
1595 int len = strlen(strings[t]);
1596 for(s=0;s<len;s++) {
1598 writeU8(table, strings[t][s]);
1603 void name_delete(ttf_t*ttf)
1605 if(ttf->full_name) {
1606 free(ttf->full_name);
1609 if(ttf->family_name) {
1610 free(ttf->family_name);
1613 if(ttf->subfamily_name) {
1614 free(ttf->subfamily_name);
1615 ttf->subfamily_name=0;
1617 if(ttf->version_string) {
1618 free(ttf->version_string);
1619 ttf->version_string=0;
1622 free(ttf->font_uid);
1625 if(ttf->postscript_name) {
1626 free(ttf->postscript_name);
1627 ttf->postscript_name=0;
1631 static table_post_t*post_new(ttf_t*ttf)
1633 table_post_t*post = rfx_calloc(sizeof(table_post_t));
1636 void post_parse(memreader_t*r, ttf_t*ttf)
1638 table_post_t*post = ttf->post = rfx_calloc(sizeof(table_post_t));
1639 U16 format = readU16(r);
1640 post->italic_angle = readU16(r);
1641 post->underline_position = readU16(r);
1642 post->underline_thickness = readU16(r);
1643 U16 is_monospaced = readU16(r);
1644 readU16(r); // min mem 42
1646 readU16(r); // min mem 1
1649 void post_write(ttf_t*ttf, ttf_table_t*table)
1651 table_post_t*post = ttf->post;
1652 writeU32(table, 0x00030000);
1653 writeU32(table, post->italic_angle);
1654 writeU16(table, post->underline_position);
1655 writeU16(table, post->underline_thickness);
1656 writeU32(table, 0); //is monospaced TODO
1657 writeU32(table, 0); //min mem 42
1659 writeU32(table, 0); //min mem 1
1662 void post_delete(ttf_t*ttf)
1670 void cvt_parse(memreader_t*r, ttf_t*ttf)
1672 table_cvt_t*cvt = ttf->cvt = rfx_calloc(sizeof(table_cvt_t));
1673 cvt->num = r->size/2;
1674 cvt->values = malloc(cvt->num*sizeof(S16));
1676 for(t=0;t<cvt->num;t++) {
1677 cvt->values[t] = readS16(r);
1680 void cvt_write(ttf_t*ttf, ttf_table_t*table)
1682 table_cvt_t*cvt = ttf->cvt;
1684 for(t=0;t<cvt->num;t++) {
1685 writeS16(table, cvt->values[t]);
1688 void cvt_delete(ttf_t*ttf)
1691 if(ttf->cvt->values)
1692 free(ttf->cvt->values);
1698 static table_gasp_t*gasp_new(ttf_t*ttf)
1700 table_gasp_t*gasp = rfx_calloc(sizeof(table_gasp_t));
1702 gasp->records = rfx_calloc(sizeof(gasp->records[0])*gasp->num);
1704 gasp->records[0].size = 65535;
1705 gasp->records[0].behaviour = 15; //gridfit+grayscale rendering
1708 void gasp_parse(memreader_t*r, ttf_t*ttf)
1710 table_gasp_t*gasp = ttf->gasp = rfx_calloc(sizeof(table_gasp_t));
1711 readU16(r); //version
1712 int num = readU16(r);
1715 gasp->records = malloc(sizeof(gasp->records[0])*num);
1716 for(t=0;t<num;t++) {
1717 gasp->records[t].size = readU16(r);
1718 gasp->records[t].behaviour = readU16(r);
1721 void gasp_write(ttf_t*ttf, ttf_table_t*table)
1723 table_gasp_t*gasp = ttf->gasp;
1725 writeU16(table, gasp->num);
1727 for(t=0;t<gasp->num;t++) {
1728 writeU16(table, gasp->records[t].size);
1729 writeU16(table, gasp->records[t].behaviour);
1732 void gasp_delete(ttf_t*ttf)
1735 if(ttf->gasp->records)
1736 free(ttf->gasp->records);
1742 void fpgm_new(ttf_t*ttf)
1744 table_code_t*fpgm = ttf->fpgm = rfx_calloc(sizeof(table_code_t));
1746 void fpgm_parse(memreader_t*r, ttf_t*ttf)
1748 table_code_t*fpgm = ttf->fpgm = rfx_calloc(sizeof(table_code_t));
1749 if(!r->size) return;
1750 fpgm->size = r->size;
1751 fpgm->code = malloc(r->size);
1752 readBlock(r, fpgm->code, r->size);
1754 void fpgm_write(ttf_t*ttf, ttf_table_t*table)
1756 table_code_t*code = ttf->fpgm;
1757 writeBlock(table, code->code, code->size);
1759 void fpgm_delete(ttf_t*ttf)
1763 free(ttf->fpgm->code);
1769 void prep_parse(memreader_t*r, ttf_t*ttf)
1771 table_code_t*prep = ttf->prep = rfx_calloc(sizeof(table_code_t));
1772 if(!r->size) return;
1773 prep->size = r->size;
1774 prep->code = malloc(r->size);
1775 readBlock(r, prep->code, r->size);
1777 void prep_write(ttf_t*ttf, ttf_table_t*table)
1779 table_code_t*code = ttf->prep;
1780 writeBlock(table, code->code, code->size);
1782 void prep_delete(ttf_t*ttf)
1786 free(ttf->prep->code);
1792 static int ttf_parse_tables(ttf_t*ttf)
1796 table = ttf_find_table(ttf, TAG_HEAD);
1798 msg("<error> Font has no head table");
1801 INIT_READ(m, table->data, table->len, 0);
1802 int loc_index = head_parse(ttf, &m);
1803 ttf_table_delete(ttf, table);
1805 table = ttf_find_table(ttf, TAG_MAXP);
1807 msg("<error> Font has no maxp table");
1810 INIT_READ(m2, table->data, table->len, 0);
1811 ttf->maxp = maxp_parse(ttf, &m2);
1812 ttf_table_delete(ttf, table);
1814 if(!ttf->num_glyphs) {
1815 msg("<error> Invalid number of characters");
1818 ttf->glyphs = rfx_calloc(sizeof(ttfglyph_t)*ttf->num_glyphs);
1820 table = ttf_find_table(ttf, TAG_OS2);
1822 INIT_READ(m, table->data, table->len, 0);
1823 ttf->os2 = os2_parse(&m);
1824 ttf_table_delete(ttf, table);
1828 table = ttf_find_table(ttf, TAG_HHEA);
1830 INIT_READ(m, table->data, table->len, 0);
1831 int num_advances = hea_parse(&m, ttf);
1832 ttf_table_delete(ttf, table);
1834 table = ttf_find_table(ttf, TAG_HMTX);
1836 INIT_READ(m, table->data, table->len, 0);
1837 mtx_parse(&m, ttf, num_advances);
1838 ttf_table_delete(ttf, table);
1841 table = ttf_find_table(ttf, TAG_VHEA);
1844 INIT_READ(m, table->data, table->len, 0);
1845 int num_advances = hea_parse(&m, ttf);
1846 ttf_table_delete(ttf, table);
1848 table = ttf_find_table(ttf, TAG_VMTX);
1850 INIT_READ(m, table->data, table->len, 0);
1851 mtx_parse(&m, ttf, num_advances);
1852 ttf_table_delete(ttf, table);
1855 msg("<error> Font contains neither HHEA nor VHEA");
1858 table = ttf_find_table(ttf, TAG_LOCA);
1860 INIT_READ(m, table->data, table->len, 0);
1861 U32*loca = loca_parse(&m, ttf, loc_index);
1862 ttf_table_delete(ttf, table);
1863 table = ttf_find_table(ttf, TAG_GLYF);
1865 INIT_READ(m, table->data, table->len, 0);
1866 glyf_parse(&m, ttf, loca);
1867 ttf_table_delete(ttf, table);
1872 table = ttf_find_table(ttf, TAG_CMAP);
1874 INIT_READ(m, table->data, table->len, 0);
1875 cmap_parse(&m, ttf);
1876 ttf_table_delete(ttf, table);
1879 table = ttf_find_table(ttf, TAG_POST);
1881 INIT_READ(m, table->data, table->len, 0);
1882 post_parse(&m, ttf);
1883 ttf_table_delete(ttf, table);
1886 table = ttf_find_table(ttf, TAG_NAME);
1888 INIT_READ(m, table->data, table->len, 0);
1889 name_parse(&m, ttf);
1890 ttf_table_delete(ttf, table);
1893 table = ttf_find_table(ttf, TAG_CVT);
1895 INIT_READ(m, table->data, table->len, 0);
1897 ttf_table_delete(ttf, table);
1900 table = ttf_find_table(ttf, TAG_GASP);
1902 INIT_READ(m, table->data, table->len, 0);
1903 gasp_parse(&m, ttf);
1904 ttf_table_delete(ttf, table);
1907 table = ttf_find_table(ttf, TAG_PREP);
1909 INIT_READ(m, table->data, table->len, 0);
1910 prep_parse(&m, ttf);
1911 ttf_table_delete(ttf, table);
1914 table = ttf_find_table(ttf, TAG_FPGM);
1916 INIT_READ(m, table->data, table->len, 0);
1917 fpgm_parse(&m, ttf);
1918 ttf_table_delete(ttf, table);
1923 static void ttf_collapse_tables(ttf_t*ttf)
1927 ttf_table_t*head = ttf_find_table(ttf, TAG_HEAD);
1929 return; //already collapsed
1932 table = ttf_addtable(ttf, TAG_MAXP);
1933 maxp_write(ttf, table);
1938 table = ttf_addtable(ttf, TAG_OS2);
1939 os2_write(ttf, table);
1944 if(!ttf->is_vertical) {
1945 table = ttf_addtable(ttf, TAG_HMTX);
1946 int num_advances = mtx_write(ttf, table);
1947 table = ttf_addtable(ttf, TAG_HHEA);
1948 hea_write(ttf, table, num_advances);
1951 table = ttf_addtable(ttf, TAG_VMTX);
1952 int num_advances = mtx_write(ttf, table);
1953 table = ttf_addtable(ttf, TAG_VHEA);
1954 hea_write(ttf, table, num_advances);
1960 if(ttf->num_glyphs) {
1962 table = ttf_addtable(ttf, TAG_CMAP);
1963 cmap_write(ttf, table);
1968 table = ttf_addtable(ttf, TAG_GLYF);
1969 U32*locations = glyf_write(ttf, table);
1970 table = ttf_addtable(ttf, TAG_LOCA);
1971 loca_size = loca_write(ttf, table, locations);
1977 if(ttf->full_name || ttf->family_name || ttf->subfamily_name || ttf->font_uid || ttf->postscript_name) {
1978 table = ttf_addtable(ttf, TAG_NAME);
1979 name_write(ttf, table);
1983 table = ttf_addtable(ttf, TAG_POST);
1984 post_write(ttf, table);
1988 table = ttf_addtable(ttf, TAG_CVT);
1989 cvt_write(ttf, table);
1993 table = ttf_addtable(ttf, TAG_GASP);
1994 gasp_write(ttf, table);
1998 table = ttf_addtable(ttf, TAG_HEAD);
1999 head_write(ttf, table, loca_size);
2005 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
2006 ttf->version = VERSION_1_0;
2009 ttf_t* ttf_load(void*data, int length)
2011 INIT_READ(r,data,length, 0);
2014 msg("<error> Truncated Truetype file (%d bytes)", length);
2018 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
2019 ttf->version = readU32(&r);
2020 if(ttf->version == SWAP32(length)) {
2021 U32 fontDataSize = readU32(&r);
2022 U32 version = readU32(&r);
2023 U32 flags = readU32(&r);
2025 readBlock(&r, panose, 10);
2026 readU8(&r); //charset
2027 readU8(&r); //italoc
2028 readU32(&r); //weight
2029 readU16(&r); //fstype
2030 U16 magic = readU16(&r); //magicNumber
2031 /* we're being paranoid: it's entirely possible for the font
2032 size to be exactly 0x10000. Only treat this font as eot if
2033 it has the right magic number */
2034 if(magic == 0x4c50) {
2035 readU32(&r); //unicoderange[0]
2036 readU32(&r); //unicoderange[1]
2037 readU32(&r); //unicoderange[2]
2038 readU32(&r); //unicoderange[3]
2039 readU32(&r); //codepagerange[0]
2040 readU32(&r); //codepagerange[1]
2041 readU32(&r); //checksumadjustment
2042 readU32(&r); //reserved[0]
2043 readU32(&r); //reserved[1]
2044 readU32(&r); //reserved[2]
2045 readU32(&r); //reserved[3]
2046 readU16(&r); //padding
2049 for(nr=0;nr<4;nr++) {
2051 /* All of ttf is big-endian. All of ttf? No. One small eot table
2052 of indomitable little-endian... */
2054 len |= readU8(&r)<<8;
2056 for(t=0;t<len;t++) {
2057 U8 c = readU16(&r)>>8;
2059 readU16(&r); // zero terminator
2061 readU16(&r); // more padding
2063 /* adjust the offset to the start of the actual truetype
2064 data- the positions in the table header will be relative
2065 to the ttf data after the header, not to the file */
2069 ttf->version = readU32(&r);
2072 ttf->version = readU32(&r);
2076 if(ttf->version == TTCFTAG) {
2077 /* a ttc collection is a number of truetype fonts
2078 packaged together */
2080 msg("<error> Truncated TTC file (%d bytes)", length);
2083 U32 ttcf_version = readU32(&r); // 0x00000100: v1.0, 0x00000200: v2.0, includes DSIG table
2084 U32 num_fonts = readU32(&r); // number of fonts
2085 U32 font1_position = readU32(&r);
2086 if(font1_position+12 > length) {\
2087 msg("<error> Truncated TTC file (%d bytes, first font at %d)", length, font1_position);
2090 r.pos = font1_position;
2091 ttf->version = readU32(&r);
2094 int num_tables = readU16(&r);
2096 readU16(&r); //search range
2097 readU16(&r); //entry selector
2098 readU16(&r); //range shift
2100 if(num_tables*16 > length) {
2101 msg("<error> Truncated TTF file (table entries: %d)", num_tables);
2102 if(ttf->version != OPENTYPE &&
2103 ttf->version != TRUETYPE_MACOS &&
2104 ttf->version != VERSION_1_0) {
2105 // bad table length, weird version. This is probably not a ttf file.
2110 U32*table_data = malloc(16*num_tables);
2112 for(t=0;t<num_tables*4;t++) {
2113 table_data[t] = readU32(&r);
2115 for(t=0;t<num_tables;t++) {
2116 U32 tag = table_data[t*4];
2117 U32 checksum = table_data[t*4+1];
2118 U32 pos = table_data[t*4+2];
2119 U32 len = table_data[t*4+3];
2121 printf("TTF Table %02x%02x%02x%02x %c%c%c%c\n",
2122 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
2123 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff
2126 if(pos+len > length) {
2127 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);
2129 U8*mem = malloc(len);
2131 readBlock(&r, mem, len);
2133 ttf_table_t*table = ttf_addtable(ttf, tag);
2135 table->len = table->memsize = len;
2137 U32 checksum2 = ttf_table_checksum(table);
2138 if(checksum2!=checksum) {
2139 msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x",
2140 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
2141 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
2142 len, checksum2, checksum);
2149 if(!ttf_parse_tables(ttf))
2154 void ttf_create_truetype_tables(ttf_t*ttf)
2157 ttf->head = head_new(ttf);
2159 ttf->maxp = maxp_new(ttf);
2161 ttf->hea = hea_new(ttf);
2163 ttf->os2 = os2_new(ttf);
2165 ttf->post = post_new(ttf);
2167 ttf->gasp = gasp_new(ttf);
2169 ttf->fpgm = fpgm_new(ttf);
2172 ttf_table_t* ttf_write(ttf_t*ttf, U32*checksum_adjust)
2174 ttf_collapse_tables(ttf);
2176 ttf_table_t*file = ttf_table_new(0);
2177 writeU32(file, VERSION_1_0);
2179 /* write number of tables */
2181 ttf_table_t*t = ttf->tables;
2186 writeU16(file, num_tables);
2188 /* write search range */
2189 int tmp = num_tables;
2190 int search_range = 0;
2197 writeU16(file, search_range);
2199 /* write entry selector */
2200 int entry_selector = 0;
2205 writeU16(file, entry_selector);
2207 /* write range shift */
2208 int range_shift = num_tables*16 - search_range;
2209 writeU16(file, range_shift);
2211 /* write table dictionary */
2212 int table_dictionary_pos = file->len;
2213 int data_pos = file->len + num_tables*16;
2214 for(t=ttf->tables;t;t=t->next) {
2215 writeU32(file, t->id);
2216 writeU32(file, ttf_table_checksum(t));
2217 writeU32(file, data_pos);
2218 writeU32(file, t->len);
2220 data_pos += (-t->len)&3; //pad
2225 U8 zero[4]={0,0,0,0};
2226 for(t=ttf->tables;t;t=t->next) {
2227 if(t->id == TAG_HEAD)
2228 head_pos = file->len;
2229 writeBlock(file, t->data, t->len);
2230 writeBlock(file, zero, (-t->len)&3); //pad
2232 U32 checksum = 0xb1b0afba - ttf_table_checksum(file);
2234 *checksum_adjust = checksum;
2235 U8*checksum2 = file->data + head_pos + 8;
2236 checksum2[0] = checksum>>24;
2237 checksum2[1] = checksum>>16;
2238 checksum2[2] = checksum>>8;
2239 checksum2[3] = checksum>>0;
2243 ttf_table_t* ttf_eot_head(ttf_t*ttf)
2245 ttf_table_t*file = ttf_table_new(0);
2246 writeU32(file, 0); //file size (filled in later)
2247 writeU32(file, 0); //fontdatasize (filled in later)
2248 writeU32(file, 0x01000200);
2249 writeU32(file, 0); //flags
2250 writeU8(file, ttf->os2->panose_FamilyType);
2251 writeU8(file, ttf->os2->panose_SerifStyle);
2252 writeU8(file, ttf->os2->panose_Weight);
2253 writeU8(file, ttf->os2->panose_Proportion);
2254 writeU8(file, ttf->os2->panose_Contrast);
2255 writeU8(file, ttf->os2->panose_StrokeVariation);
2256 writeU8(file, ttf->os2->panose_ArmStyle);
2257 writeU8(file, ttf->os2->panose_Letterform);
2258 writeU8(file, ttf->os2->panose_Midline);
2259 writeU8(file, ttf->os2->panose_XHeight);
2260 writeU8(file, 1); //charset (default)
2261 writeU8(file, ttf->os2->fsSelection&1); //italic
2262 writeU32_LE(file, ttf->os2->usWeightClass);
2263 writeU16(file, 0); //fstype
2264 writeU16(file, 0x4c50); //magic
2265 writeU32_LE(file, ttf->os2->ulCharRange[0]);
2266 writeU32_LE(file, ttf->os2->ulCharRange[1]);
2267 writeU32_LE(file, ttf->os2->ulCharRange[2]);
2268 writeU32_LE(file, ttf->os2->ulCharRange[3]);
2269 writeU32_LE(file, ttf->os2->ulCodePageRange1);
2270 writeU32_LE(file, ttf->os2->ulCodePageRange2);
2271 writeU32(file, 0); //checksum adjust (filled in later)
2272 writeU32(file, 0); //reserved[0]
2273 writeU32(file, 0); //reserved[1]
2274 writeU32(file, 0); //reserved[2]
2275 writeU32(file, 0); //reserved[3]
2276 writeU16(file, 0); //padding(1)
2280 char* strings[] = {ttf->family_name, ttf->subfamily_name, ttf->version_string, ttf->full_name};
2281 int nr = sizeof(strings)/sizeof(strings[0]);
2284 char *string = strings[i];
2287 len = strlen(string);
2288 writeU16_LE(file, len*2);
2289 for(t=0;t<len;t++) {
2291 writeU8(file, string[t]);
2293 writeU16(file, 0); //zero byte pad
2296 writeU16(file, 0); //zero byte pad
2298 writeU16(file, 0); //padding(2)
2302 void ttf_save_eot(ttf_t*ttf, const char*filename)
2304 ttf_table_t* eot = ttf_eot_head(ttf);
2305 U32 checksum_adjust = 0;
2306 ttf_table_t* t = ttf_write(ttf, &checksum_adjust);
2308 U8*len_data = eot->data;
2309 U32 full_len = eot->len + t->len;
2310 len_data[0] = full_len>>0;
2311 len_data[1] = full_len>>8;
2312 len_data[2] = full_len>>16;
2313 len_data[3] = full_len>>24;
2315 U8*len_data2 = eot->data+4;
2316 len_data2[0] = t->len>>0;
2317 len_data2[1] = t->len>>8;
2318 len_data2[2] = t->len>>16;
2319 len_data2[3] = t->len>>24;
2321 U8*checksum_data = eot->data + 60;
2322 checksum_data[0] = checksum_adjust>>0;
2323 checksum_data[1] = checksum_adjust>>8;
2324 checksum_data[2] = checksum_adjust>>16;
2325 checksum_data[3] = checksum_adjust>>24;
2327 FILE*fi = fopen(filename, "wb");
2333 fwrite(eot->data, eot->len, 1, fi);
2334 fwrite(t->data, t->len, 1, fi);
2336 ttf_table_delete(0, t);
2337 ttf_table_delete(0, eot);
2340 void ttf_save(ttf_t*ttf, const char*filename)
2342 ttf_table_t* t = ttf_write(ttf, 0);
2343 FILE*fi = fopen(filename, "wb");
2348 fwrite(t->data, t->len, 1, fi);
2350 ttf_table_delete(0, t);
2353 void ttf_dump(ttf_t*ttf)
2355 msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
2356 ttf_table_t*table = ttf->tables;
2358 U32 tag = table->id;
2359 msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)",
2360 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
2361 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
2362 table = table->next;
2364 //ttf_table_dump(ttf_find_table(ttf, TAG_MAXP));
2372 void ttf_destroy_tables(ttf_t*ttf)
2374 ttf_table_t*table = ttf->tables;
2376 ttf_table_t*next = table->next;
2383 void ttf_reduce(ttf_t*ttf)
2385 ttf_destroy_tables(ttf);
2387 void ttf_destroy(ttf_t*ttf)
2389 ttf_destroy_tables(ttf);
2402 int main(int argn, const char*argv[])
2404 setConsoleLogging(7);
2405 const char*filename = "comic.ttf";
2408 //msg("<notice> Loading %s", filename);
2409 memfile_t*m = memfile_open(filename);
2410 ttf_t*ttf = ttf_load(m->data, m->len);
2413 msg("<error> Couldn't load %s", filename);
2418 ttf->full_name = strdup("Test-Normal");
2419 ttf->family_name = strdup("Test");
2420 ttf->subfamily_name = strdup("Normal");
2421 ttf->version_string = strdup("Version 1.0");
2422 ttf->font_uid = strdup("omguid");
2423 ttf->postscript_name = strdup("Test-psname");
2428 //printf("os2 version: %04x (%d), maxp size: %d\n",
2429 // ttf->os2->version, ttf->os2->size, ttf->maxp->size);
2430 ttf_save_eot(ttf, "testfont.eot");
2431 ttf_save(ttf, "testfont.ttf");