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>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) {
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 writeS16(w, ttf->glyphs[t].bearing);
854 for(;t<ttf->num_glyphs;t++) {
855 writeS16(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;
1422 while(tmp>1) {tmp>>=1;entry_selector++;}
1423 w->data[num_segments_pos++]=entry_selector>>8;
1424 w->data[num_segments_pos++]=entry_selector;
1425 /* backpatch range shift */
1426 int range_shift = num_segments*2 - search_range*2;
1427 w->data[num_segments_pos++]=range_shift>>8;
1428 w->data[num_segments_pos++]=range_shift;
1432 while(pos < ttf->unicode_size) {
1433 if(!ttf->unicode[pos]) {
1437 U16 end = segment_size(ttf->unicode, pos, ttf->unicode_size);
1438 w->data[end_pos++]=end>>8;
1439 w->data[end_pos++]=end;
1440 w->data[start_pos++]=pos>>8;
1441 w->data[start_pos++]=pos;
1443 U16 delta = ttf->unicode[pos]-pos;
1445 for(s=pos+1;s<=end;s++) {
1446 U16 delta2 = ttf->unicode[s]-s;
1457 range = w->len - range_pos;
1458 for(s=pos;s<=end;s++) {
1459 writeU16(w, ttf->unicode[s]);
1462 w->data[delta_pos++]=delta>>8;
1463 w->data[delta_pos++]=delta;
1464 w->data[range_pos++]=range>>8;
1465 w->data[range_pos++]=range;
1470 /* write out a mapping from 0xffff to 0- seems to be required
1471 by some libraries (e.g. fonttools) */
1472 w->data[end_pos++]=0xff;
1473 w->data[end_pos++]=0xff;
1474 w->data[start_pos++]=0xff;
1475 w->data[start_pos++]=0xff;
1476 w->data[delta_pos++]=0;
1477 w->data[delta_pos++]=1;
1478 w->data[range_pos++]=0;
1479 w->data[range_pos++]=0;
1481 w->data[length_pos]=(w->len-20)>>8;
1482 w->data[length_pos+1]=w->len-20;
1484 void cmap_delete(ttf_t*ttf)
1490 ttf->unicode_size=0;
1492 static char*readString(memreader_t*r, int len)
1494 char*s = malloc(len+1);
1495 readBlock(r, s, len);
1499 void name_parse(memreader_t*r, ttf_t*ttf)
1501 U16 format = readU16(r);
1502 U16 count = readU16(r);
1503 U16 offset = readU16(r);
1506 for(t=0;t<count;t++) {
1507 U16 platform = readU16(r);
1508 U16 encoding = readU16(r);
1509 U16 language = readU16(r);
1510 U16 name_id = readU16(r);
1511 U16 len = readU16(r);
1512 U16 offset_2 = readU16(r);
1514 char ** read_name = 0;
1516 INIT_READ(ss, r->mem, r->size, offset+offset_2);
1517 if(!(platform==0 || (platform==1 && encoding==0)))
1520 INIT_READ(s, r->mem, r->size, offset+offset_2);
1523 case 1: read_name = &ttf->family_name; break;
1524 case 2: read_name = &ttf->subfamily_name; break;
1525 case 3: read_name = &ttf->font_uid; break;
1526 case 4: read_name = &ttf->full_name; break;
1527 case 5: read_name = &ttf->version_string; break;
1528 case 6: read_name = &ttf->postscript_name; break;
1529 default: read_name = 0;
1533 if (*read_name) free(*read_name);
1534 *read_name = readString(&s, len);
1538 void name_write(ttf_t*ttf, ttf_table_t*table)
1540 char*strings[6] = {ttf->family_name, ttf->subfamily_name, ttf->font_uid, ttf->full_name, ttf->version_string, ttf->postscript_name};
1541 int codes[6] = {1,2,3,4,5,6};
1543 writeU16(table, 0); //format
1546 int nr = sizeof(strings)/sizeof(strings[0]);
1552 writeU16(table, count); //count
1554 int offset_pos = table->len;
1555 writeU16(table, 0); //offset (will be filled in later)
1557 /* Windows expects the name table to be sorted by platform/encoding/language/name_id */
1561 writeU16(table, 1); //platform id (mac)
1562 writeU16(table, 0); //encoding id (latin-1)
1563 writeU16(table, 0); //language (english)
1564 writeU16(table, codes[t]);
1565 int len = strlen(strings[t]);
1566 writeU16(table, len);
1567 writeU16(table, offset);
1573 writeU16(table, 3); //platform id (windows)
1574 writeU16(table, 1); //encoding id (ucs-2)
1575 writeU16(table, 0x409); //language (US)
1576 writeU16(table, codes[t]);
1577 int len2 = strlen(strings[t]) * 2;
1578 writeU16(table, len2);
1579 writeU16(table, offset);
1584 table->data[offset_pos] = table->len>>8;
1585 table->data[offset_pos+1] = table->len;
1589 int len = strlen(strings[t]);
1590 writeBlock(table, strings[t], len);
1596 int len = strlen(strings[t]);
1597 for(s=0;s<len;s++) {
1599 writeU8(table, strings[t][s]);
1604 void name_delete(ttf_t*ttf)
1606 if(ttf->full_name) {
1607 free(ttf->full_name);
1610 if(ttf->family_name) {
1611 free(ttf->family_name);
1614 if(ttf->subfamily_name) {
1615 free(ttf->subfamily_name);
1616 ttf->subfamily_name=0;
1618 if(ttf->version_string) {
1619 free(ttf->version_string);
1620 ttf->version_string=0;
1623 free(ttf->font_uid);
1626 if(ttf->postscript_name) {
1627 free(ttf->postscript_name);
1628 ttf->postscript_name=0;
1632 static table_post_t*post_new(ttf_t*ttf)
1634 table_post_t*post = rfx_calloc(sizeof(table_post_t));
1637 void post_parse(memreader_t*r, ttf_t*ttf)
1639 table_post_t*post = ttf->post = rfx_calloc(sizeof(table_post_t));
1640 U16 format = readU16(r);
1641 post->italic_angle = readU16(r);
1642 post->underline_position = readU16(r);
1643 post->underline_thickness = readU16(r);
1644 U16 is_monospaced = readU16(r);
1645 readU16(r); // min mem 42
1647 readU16(r); // min mem 1
1650 void post_write(ttf_t*ttf, ttf_table_t*table)
1652 table_post_t*post = ttf->post;
1653 writeU32(table, 0x00030000);
1654 writeU32(table, post->italic_angle);
1655 writeU16(table, post->underline_position);
1656 writeU16(table, post->underline_thickness);
1657 writeU32(table, 0); //is monospaced TODO
1658 writeU32(table, 0); //min mem 42
1660 writeU32(table, 0); //min mem 1
1663 void post_delete(ttf_t*ttf)
1671 void cvt_parse(memreader_t*r, ttf_t*ttf)
1673 table_cvt_t*cvt = ttf->cvt = rfx_calloc(sizeof(table_cvt_t));
1674 cvt->num = r->size/2;
1675 cvt->values = malloc(cvt->num*sizeof(S16));
1677 for(t=0;t<cvt->num;t++) {
1678 cvt->values[t] = readS16(r);
1681 void cvt_write(ttf_t*ttf, ttf_table_t*table)
1683 table_cvt_t*cvt = ttf->cvt;
1685 for(t=0;t<cvt->num;t++) {
1686 writeS16(table, cvt->values[t]);
1689 void cvt_delete(ttf_t*ttf)
1692 if(ttf->cvt->values)
1693 free(ttf->cvt->values);
1699 static table_gasp_t*gasp_new(ttf_t*ttf)
1701 table_gasp_t*gasp = rfx_calloc(sizeof(table_gasp_t));
1703 gasp->records = rfx_calloc(sizeof(gasp->records[0])*gasp->num);
1705 gasp->records[0].size = 65535;
1706 gasp->records[0].behaviour = 15; //gridfit+grayscale rendering
1709 void gasp_parse(memreader_t*r, ttf_t*ttf)
1711 table_gasp_t*gasp = ttf->gasp = rfx_calloc(sizeof(table_gasp_t));
1712 readU16(r); //version
1713 int num = readU16(r);
1716 gasp->records = malloc(sizeof(gasp->records[0])*num);
1717 for(t=0;t<num;t++) {
1718 gasp->records[t].size = readU16(r);
1719 gasp->records[t].behaviour = readU16(r);
1722 void gasp_write(ttf_t*ttf, ttf_table_t*table)
1724 table_gasp_t*gasp = ttf->gasp;
1726 writeU16(table, gasp->num);
1728 for(t=0;t<gasp->num;t++) {
1729 writeU16(table, gasp->records[t].size);
1730 writeU16(table, gasp->records[t].behaviour);
1733 void gasp_delete(ttf_t*ttf)
1736 if(ttf->gasp->records)
1737 free(ttf->gasp->records);
1743 table_code_t*prep_new(ttf_t*ttf)
1745 table_code_t*prep = ttf->prep = rfx_calloc(sizeof(table_code_t));
1746 ttf_table_t*t = ttf_table_new(0);
1747 writeU8(t,0xb8);writeU16(t,0x1ff); // pushword(0x1ff)
1748 writeU8(t,0x85); //scanctrl (always do dropout, for all sizes)
1749 writeU8(t,0xb0);writeU8(t,1); // pushbyte(1)
1750 writeU8(t,0x8d); //scantype (simple dropout control w/o stubs)
1751 writeU8(t,0xb0);writeU8(t,5); // pushbyte(5)
1752 writeU8(t,0x8d); //scantype (for windows) smart dropout control w/o stubs
1753 prep->code = t->data;
1754 prep->size = t->len;
1759 void fpgm_parse(memreader_t*r, ttf_t*ttf)
1761 table_code_t*fpgm = ttf->fpgm = rfx_calloc(sizeof(table_code_t));
1762 if(!r->size) return;
1763 fpgm->size = r->size;
1764 fpgm->code = malloc(r->size);
1765 readBlock(r, fpgm->code, r->size);
1767 void fpgm_write(ttf_t*ttf, ttf_table_t*table)
1769 table_code_t*code = ttf->fpgm;
1770 writeBlock(table, code->code, code->size);
1772 void fpgm_delete(ttf_t*ttf)
1776 free(ttf->fpgm->code);
1782 void prep_parse(memreader_t*r, ttf_t*ttf)
1784 table_code_t*prep = ttf->prep = rfx_calloc(sizeof(table_code_t));
1785 if(!r->size) return;
1786 prep->size = r->size;
1787 prep->code = malloc(r->size);
1788 readBlock(r, prep->code, r->size);
1790 void prep_write(ttf_t*ttf, ttf_table_t*table)
1792 table_code_t*code = ttf->prep;
1793 writeBlock(table, code->code, code->size);
1795 void prep_delete(ttf_t*ttf)
1799 free(ttf->prep->code);
1805 static int ttf_parse_tables(ttf_t*ttf)
1809 table = ttf_find_table(ttf, TAG_HEAD);
1811 msg("<error> Font has no head table");
1814 INIT_READ(m, table->data, table->len, 0);
1815 int loc_index = head_parse(ttf, &m);
1816 ttf_table_delete(ttf, table);
1818 table = ttf_find_table(ttf, TAG_MAXP);
1820 msg("<error> Font has no maxp table");
1823 INIT_READ(m2, table->data, table->len, 0);
1824 ttf->maxp = maxp_parse(ttf, &m2);
1825 ttf_table_delete(ttf, table);
1827 if(!ttf->num_glyphs) {
1828 msg("<error> Invalid number of characters");
1831 ttf->glyphs = rfx_calloc(sizeof(ttfglyph_t)*ttf->num_glyphs);
1833 table = ttf_find_table(ttf, TAG_OS2);
1835 INIT_READ(m, table->data, table->len, 0);
1836 ttf->os2 = os2_parse(&m);
1837 ttf_table_delete(ttf, table);
1841 table = ttf_find_table(ttf, TAG_HHEA);
1843 INIT_READ(m, table->data, table->len, 0);
1844 int num_advances = hea_parse(&m, ttf);
1845 ttf_table_delete(ttf, table);
1847 table = ttf_find_table(ttf, TAG_HMTX);
1849 INIT_READ(m, table->data, table->len, 0);
1850 mtx_parse(&m, ttf, num_advances);
1851 ttf_table_delete(ttf, table);
1854 table = ttf_find_table(ttf, TAG_VHEA);
1857 INIT_READ(m, table->data, table->len, 0);
1858 int num_advances = hea_parse(&m, ttf);
1859 ttf_table_delete(ttf, table);
1861 table = ttf_find_table(ttf, TAG_VMTX);
1863 INIT_READ(m, table->data, table->len, 0);
1864 mtx_parse(&m, ttf, num_advances);
1865 ttf_table_delete(ttf, table);
1868 msg("<error> Font contains neither HHEA nor VHEA");
1871 table = ttf_find_table(ttf, TAG_LOCA);
1873 INIT_READ(m, table->data, table->len, 0);
1874 U32*loca = loca_parse(&m, ttf, loc_index);
1875 ttf_table_delete(ttf, table);
1876 table = ttf_find_table(ttf, TAG_GLYF);
1878 INIT_READ(m, table->data, table->len, 0);
1879 glyf_parse(&m, ttf, loca);
1880 ttf_table_delete(ttf, table);
1885 table = ttf_find_table(ttf, TAG_CMAP);
1887 INIT_READ(m, table->data, table->len, 0);
1888 cmap_parse(&m, ttf);
1889 ttf_table_delete(ttf, table);
1892 table = ttf_find_table(ttf, TAG_POST);
1894 INIT_READ(m, table->data, table->len, 0);
1895 post_parse(&m, ttf);
1896 ttf_table_delete(ttf, table);
1899 table = ttf_find_table(ttf, TAG_NAME);
1901 INIT_READ(m, table->data, table->len, 0);
1902 name_parse(&m, ttf);
1903 ttf_table_delete(ttf, table);
1906 table = ttf_find_table(ttf, TAG_CVT);
1908 INIT_READ(m, table->data, table->len, 0);
1910 ttf_table_delete(ttf, table);
1913 table = ttf_find_table(ttf, TAG_GASP);
1915 INIT_READ(m, table->data, table->len, 0);
1916 gasp_parse(&m, ttf);
1917 ttf_table_delete(ttf, table);
1920 table = ttf_find_table(ttf, TAG_PREP);
1922 INIT_READ(m, table->data, table->len, 0);
1923 prep_parse(&m, ttf);
1924 ttf_table_delete(ttf, table);
1927 table = ttf_find_table(ttf, TAG_FPGM);
1929 INIT_READ(m, table->data, table->len, 0);
1930 fpgm_parse(&m, ttf);
1931 ttf_table_delete(ttf, table);
1936 static void ttf_collapse_tables(ttf_t*ttf)
1940 ttf_table_t*head = ttf_find_table(ttf, TAG_HEAD);
1942 return; //already collapsed
1945 table = ttf_addtable(ttf, TAG_MAXP);
1946 maxp_write(ttf, table);
1951 table = ttf_addtable(ttf, TAG_OS2);
1952 os2_write(ttf, table);
1957 if(!ttf->is_vertical) {
1958 table = ttf_addtable(ttf, TAG_HMTX);
1959 int num_advances = mtx_write(ttf, table);
1960 table = ttf_addtable(ttf, TAG_HHEA);
1961 hea_write(ttf, table, num_advances);
1964 table = ttf_addtable(ttf, TAG_VMTX);
1965 int num_advances = mtx_write(ttf, table);
1966 table = ttf_addtable(ttf, TAG_VHEA);
1967 hea_write(ttf, table, num_advances);
1973 if(ttf->num_glyphs) {
1975 table = ttf_addtable(ttf, TAG_CMAP);
1976 cmap_write(ttf, table);
1981 table = ttf_addtable(ttf, TAG_GLYF);
1982 U32*locations = glyf_write(ttf, table);
1983 table = ttf_addtable(ttf, TAG_LOCA);
1984 loca_size = loca_write(ttf, table, locations);
1990 if(ttf->full_name || ttf->family_name || ttf->subfamily_name || ttf->font_uid || ttf->postscript_name) {
1991 table = ttf_addtable(ttf, TAG_NAME);
1992 name_write(ttf, table);
1996 table = ttf_addtable(ttf, TAG_POST);
1997 post_write(ttf, table);
2001 table = ttf_addtable(ttf, TAG_CVT);
2002 cvt_write(ttf, table);
2006 table = ttf_addtable(ttf, TAG_GASP);
2007 gasp_write(ttf, table);
2011 table = ttf_addtable(ttf, TAG_FPGM);
2012 fpgm_write(ttf, table);
2016 table = ttf_addtable(ttf, TAG_PREP);
2017 prep_write(ttf, table);
2021 table = ttf_addtable(ttf, TAG_HEAD);
2022 head_write(ttf, table, loca_size);
2028 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
2029 ttf->version = VERSION_1_0;
2032 ttf_t* ttf_load(void*data, int length)
2034 INIT_READ(r,data,length, 0);
2037 msg("<error> Truncated Truetype file (%d bytes)", length);
2041 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
2042 ttf->version = readU32(&r);
2043 if(ttf->version == SWAP32(length)) {
2044 U32 fontDataSize = readU32(&r);
2045 U32 version = readU32(&r);
2046 U32 flags = readU32(&r);
2048 readBlock(&r, panose, 10);
2049 readU8(&r); //charset
2050 readU8(&r); //italoc
2051 readU32(&r); //weight
2052 readU16(&r); //fstype
2053 U16 magic = readU16(&r); //magicNumber
2054 /* we're being paranoid: it's entirely possible for the font
2055 size to be exactly 0x10000. Only treat this font as eot if
2056 it has the right magic number */
2057 if(magic == 0x4c50) {
2058 readU32(&r); //unicoderange[0]
2059 readU32(&r); //unicoderange[1]
2060 readU32(&r); //unicoderange[2]
2061 readU32(&r); //unicoderange[3]
2062 readU32(&r); //codepagerange[0]
2063 readU32(&r); //codepagerange[1]
2064 readU32(&r); //checksumadjustment
2065 readU32(&r); //reserved[0]
2066 readU32(&r); //reserved[1]
2067 readU32(&r); //reserved[2]
2068 readU32(&r); //reserved[3]
2069 readU16(&r); //padding
2072 for(nr=0;nr<4;nr++) {
2074 /* All of ttf is big-endian. All of ttf? No. One small eot table
2075 of indomitable little-endian... */
2077 len |= readU8(&r)<<8;
2079 for(t=0;t<len;t++) {
2080 U8 c = readU16(&r)>>8;
2082 readU16(&r); // zero terminator
2084 readU16(&r); // more padding
2086 /* adjust the offset to the start of the actual truetype
2087 data- the positions in the table header will be relative
2088 to the ttf data after the header, not to the file */
2092 ttf->version = readU32(&r);
2095 ttf->version = readU32(&r);
2099 if(ttf->version == TTCFTAG) {
2100 /* a ttc collection is a number of truetype fonts
2101 packaged together */
2103 msg("<error> Truncated TTC file (%d bytes)", length);
2106 U32 ttcf_version = readU32(&r); // 0x00000100: v1.0, 0x00000200: v2.0, includes DSIG table
2107 U32 num_fonts = readU32(&r); // number of fonts
2108 U32 font1_position = readU32(&r);
2109 if(font1_position+12 > length) {\
2110 msg("<error> Truncated TTC file (%d bytes, first font at %d)", length, font1_position);
2113 r.pos = font1_position;
2114 ttf->version = readU32(&r);
2117 int num_tables = readU16(&r);
2119 readU16(&r); //search range
2120 readU16(&r); //entry selector
2121 readU16(&r); //range shift
2123 if(num_tables*16 > length) {
2124 msg("<error> Truncated TTF file (table entries: %d)", num_tables);
2125 if(ttf->version != OPENTYPE &&
2126 ttf->version != TRUETYPE_MACOS &&
2127 ttf->version != VERSION_1_0) {
2128 // bad table length, weird version. This is probably not a ttf file.
2133 U32*table_data = malloc(16*num_tables);
2135 for(t=0;t<num_tables*4;t++) {
2136 table_data[t] = readU32(&r);
2138 for(t=0;t<num_tables;t++) {
2139 U32 tag = table_data[t*4];
2140 U32 checksum = table_data[t*4+1];
2141 U32 pos = table_data[t*4+2];
2142 U32 len = table_data[t*4+3];
2144 if(pos+len > length) {
2145 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);
2147 U8*mem = malloc(len);
2149 readBlock(&r, mem, len);
2151 ttf_table_t*table = ttf_addtable(ttf, tag);
2153 table->len = table->memsize = len;
2155 U32 checksum2 = ttf_table_checksum(table);
2156 if(checksum2!=checksum) {
2157 msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x",
2158 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
2159 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
2160 len, checksum2, checksum);
2167 if(!ttf_parse_tables(ttf))
2172 void ttf_create_truetype_tables(ttf_t*ttf)
2175 ttf->head = head_new(ttf);
2177 ttf->maxp = maxp_new(ttf);
2179 ttf->hea = hea_new(ttf);
2181 ttf->os2 = os2_new(ttf);
2183 ttf->post = post_new(ttf);
2185 ttf->gasp = gasp_new(ttf);
2187 ttf->prep = prep_new(ttf);
2190 ttf_table_t* ttf_write(ttf_t*ttf, U32*checksum_adjust)
2192 ttf_collapse_tables(ttf);
2194 ttf_table_t*file = ttf_table_new(0);
2195 writeU32(file, VERSION_1_0);
2197 /* write number of tables */
2199 ttf_table_t*t = ttf->tables;
2204 writeU16(file, num_tables);
2206 /* write search range */
2207 int tmp = num_tables;
2208 int search_range = 0;
2215 writeU16(file, search_range);
2217 /* write entry selector */
2218 int entry_selector = 0;
2223 writeU16(file, entry_selector);
2225 /* write range shift */
2226 int range_shift = num_tables*16 - search_range;
2227 writeU16(file, range_shift);
2229 /* write table dictionary */
2230 int table_dictionary_pos = file->len;
2231 int data_pos = file->len + num_tables*16;
2232 for(t=ttf->tables;t;t=t->next) {
2233 writeU32(file, t->id);
2234 writeU32(file, ttf_table_checksum(t));
2235 writeU32(file, data_pos);
2236 writeU32(file, t->len);
2238 data_pos += (-t->len)&3; //pad
2243 U8 zero[4]={0,0,0,0};
2244 for(t=ttf->tables;t;t=t->next) {
2245 if(t->id == TAG_HEAD)
2246 head_pos = file->len;
2247 writeBlock(file, t->data, t->len);
2248 writeBlock(file, zero, (-t->len)&3); //pad
2250 U32 checksum = 0xb1b0afba - ttf_table_checksum(file);
2252 *checksum_adjust = checksum;
2253 U8*checksum2 = file->data + head_pos + 8;
2254 checksum2[0] = checksum>>24;
2255 checksum2[1] = checksum>>16;
2256 checksum2[2] = checksum>>8;
2257 checksum2[3] = checksum>>0;
2261 ttf_table_t* ttf_eot_head(ttf_t*ttf)
2263 ttf_table_t*file = ttf_table_new(0);
2264 writeU32(file, 0); //file size (filled in later)
2265 writeU32(file, 0); //fontdatasize (filled in later)
2266 writeU32(file, 0x01000200);
2267 writeU32(file, 0); //flags
2268 writeU8(file, ttf->os2->panose_FamilyType);
2269 writeU8(file, ttf->os2->panose_SerifStyle);
2270 writeU8(file, ttf->os2->panose_Weight);
2271 writeU8(file, ttf->os2->panose_Proportion);
2272 writeU8(file, ttf->os2->panose_Contrast);
2273 writeU8(file, ttf->os2->panose_StrokeVariation);
2274 writeU8(file, ttf->os2->panose_ArmStyle);
2275 writeU8(file, ttf->os2->panose_Letterform);
2276 writeU8(file, ttf->os2->panose_Midline);
2277 writeU8(file, ttf->os2->panose_XHeight);
2278 writeU8(file, 1); //charset (default)
2279 writeU8(file, ttf->os2->fsSelection&1); //italic
2280 writeU32_LE(file, ttf->os2->usWeightClass);
2281 writeU16(file, 0); //fstype
2282 writeU16(file, 0x4c50); //magic
2283 writeU32_LE(file, ttf->os2->ulCharRange[0]);
2284 writeU32_LE(file, ttf->os2->ulCharRange[1]);
2285 writeU32_LE(file, ttf->os2->ulCharRange[2]);
2286 writeU32_LE(file, ttf->os2->ulCharRange[3]);
2287 writeU32_LE(file, ttf->os2->ulCodePageRange1);
2288 writeU32_LE(file, ttf->os2->ulCodePageRange2);
2289 writeU32(file, 0); //checksum adjust (filled in later)
2290 writeU32(file, 0); //reserved[0]
2291 writeU32(file, 0); //reserved[1]
2292 writeU32(file, 0); //reserved[2]
2293 writeU32(file, 0); //reserved[3]
2294 writeU16(file, 0); //padding(1)
2298 char* strings[] = {ttf->family_name, ttf->subfamily_name, ttf->version_string, ttf->full_name};
2299 int nr = sizeof(strings)/sizeof(strings[0]);
2302 char *string = strings[i];
2305 len = strlen(string);
2306 writeU16_LE(file, len*2);
2307 for(t=0;t<len;t++) {
2309 writeU8(file, string[t]);
2311 writeU16(file, 0); //zero byte pad
2314 writeU16(file, 0); //zero byte pad
2316 writeU16(file, 0); //padding(2)
2320 void ttf_save_eot(ttf_t*ttf, const char*filename)
2322 ttf_table_t* eot = ttf_eot_head(ttf);
2323 U32 checksum_adjust = 0;
2324 ttf_table_t* t = ttf_write(ttf, &checksum_adjust);
2326 U8*len_data = eot->data;
2327 U32 full_len = eot->len + t->len;
2328 len_data[0] = full_len>>0;
2329 len_data[1] = full_len>>8;
2330 len_data[2] = full_len>>16;
2331 len_data[3] = full_len>>24;
2333 U8*len_data2 = eot->data+4;
2334 len_data2[0] = t->len>>0;
2335 len_data2[1] = t->len>>8;
2336 len_data2[2] = t->len>>16;
2337 len_data2[3] = t->len>>24;
2339 U8*checksum_data = eot->data + 60;
2340 checksum_data[0] = checksum_adjust>>0;
2341 checksum_data[1] = checksum_adjust>>8;
2342 checksum_data[2] = checksum_adjust>>16;
2343 checksum_data[3] = checksum_adjust>>24;
2345 FILE*fi = fopen(filename, "wb");
2351 fwrite(eot->data, eot->len, 1, fi);
2352 fwrite(t->data, t->len, 1, fi);
2354 ttf_table_delete(0, t);
2355 ttf_table_delete(0, eot);
2358 void ttf_save(ttf_t*ttf, const char*filename)
2360 ttf_table_t* t = ttf_write(ttf, 0);
2361 FILE*fi = fopen(filename, "wb");
2366 fwrite(t->data, t->len, 1, fi);
2368 ttf_table_delete(0, t);
2371 void ttf_dump(ttf_t*ttf)
2373 msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
2374 ttf_table_t*table = ttf->tables;
2376 U32 tag = table->id;
2377 msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)",
2378 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
2379 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
2380 table = table->next;
2382 //ttf_table_dump(ttf_find_table(ttf, TAG_MAXP));
2390 void ttf_destroy_tables(ttf_t*ttf)
2392 ttf_table_t*table = ttf->tables;
2394 ttf_table_t*next = table->next;
2401 void ttf_reduce(ttf_t*ttf)
2403 ttf_destroy_tables(ttf);
2405 void ttf_destroy(ttf_t*ttf)
2407 ttf_destroy_tables(ttf);
2420 int main(int argn, const char*argv[])
2422 setConsoleLogging(7);
2423 const char*filename = "comic.ttf";
2426 //msg("<notice> Loading %s", filename);
2427 memfile_t*m = memfile_open(filename);
2428 ttf_t*ttf = ttf_load(m->data, m->len);
2431 msg("<error> Couldn't load %s", filename);
2436 ttf_create_truetype_tables(ttf);
2441 //printf("os2 version: %04x (%d), maxp size: %d\n",
2442 // ttf->os2->version, ttf->os2->size, ttf->maxp->size);
2443 ttf_save_eot(ttf, "testfont.eot");
2444 ttf_save(ttf, "testfont.ttf");