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;
641 maxp->maxZones = 2; // we don't use the Z0 zone
644 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
646 U32 version = readU32(r);
647 ttf->num_glyphs = readU16(r);
648 /* according to freetype, older fonts (version<0x10000)
649 apparently only contain the number of glyphs. this is
650 rather rare, though. */
651 if(version<0x10000 && r->size==6) return 0;
654 msg("<warning> Truncated maxp table (version %d)", version);
656 table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
657 maxp->maxPoints = readU16(r);
658 maxp->maxContours = readU16(r);
659 maxp->maxComponentPoints = readU16(r);
660 maxp->maxComponentContours = readU16(r);
661 maxp->maxZones = readU16(r);
662 maxp->maxTwilightPoints = readU16(r);
663 maxp->maxStorage = readU16(r);
664 maxp->maxFunctionDefs = readU16(r);
665 maxp->maxInstructionDefs = readU16(r);
666 maxp->maxStackElements = readU16(r);
667 maxp->maxSizeOfInstructions = readU16(r);
668 maxp->maxComponentElements = readU16(r);
669 maxp->maxComponentDepth = readU16(r);
672 static void maxp_write(ttf_t*ttf, ttf_table_t*w)
674 table_maxp_t*maxp = ttf->maxp;
676 /* version 0.5 simplified maxp table */
677 writeU32(w, 0x00005000);
678 writeU16(w, ttf->num_glyphs);
681 writeU32(w, 0x10000); //version
682 writeU16(w, ttf->num_glyphs);
683 writeU16(w, maxp->maxPoints);
684 writeU16(w, maxp->maxContours);
685 writeU16(w, maxp->maxComponentPoints);
686 writeU16(w, maxp->maxComponentContours);
687 writeU16(w, maxp->maxZones);
688 writeU16(w, maxp->maxTwilightPoints);
689 writeU16(w, maxp->maxStorage);
690 writeU16(w, maxp->maxFunctionDefs);
691 writeU16(w, maxp->maxInstructionDefs);
692 writeU16(w, maxp->maxStackElements);
693 writeU16(w, maxp->maxSizeOfInstructions);
694 writeU16(w, maxp->maxComponentElements);
695 writeU16(w, maxp->maxComponentDepth);
697 static void maxp_dump(ttf_t*ttf)
699 table_maxp_t*maxp = ttf->maxp;
701 printf("maxp->maxPoints: %d\n", maxp->maxPoints);
702 printf("maxp->maxContours: %d\n", maxp->maxContours);
703 printf("maxp->maxComponentPoints: %d\n", maxp->maxComponentPoints);
704 printf("maxp->maxComponentContours: %d\n", maxp->maxComponentContours);
705 printf("maxp->maxZones: %d\n", maxp->maxZones);
706 printf("maxp->maxTwilightPoints: %d\n", maxp->maxTwilightPoints);
707 printf("maxp->maxStorage: %d\n", maxp->maxStorage);
708 printf("maxp->maxFunctionDefs: %d\n", maxp->maxFunctionDefs);
709 printf("maxp->maxInstructionDefs: %d\n", maxp->maxInstructionDefs);
710 printf("maxp->maxStackElements: %d\n", maxp->maxStackElements);
711 printf("maxp->maxSizeOfInstructions: %d\n", maxp->maxSizeOfInstructions);
712 printf("maxp->maxComponentElements: %d\n", maxp->maxComponentElements);
713 printf("maxp->maxComponentDepth: %d\n", maxp->maxComponentDepth);
715 static void maxp_delete(ttf_t*ttf)
722 static table_hea_t*hea_new(ttf_t*ttf)
724 table_hea_t*hea = rfx_calloc(sizeof(table_hea_t));
725 if(ttf->num_glyphs) {
727 for(t=0;t<ttf->num_glyphs;t++) {
728 if(ttf->glyphs[t].advance > hea->advanceWidthMax)
729 hea->advanceWidthMax = ttf->glyphs[t].advance;
730 if(ttf->glyphs[t].bearing < hea->minLeftSideBearing)
731 hea->minLeftSideBearing = ttf->glyphs[t].bearing;
732 if(ttf->glyphs[t].xmax < hea->minRightSideBearing)
733 hea->minRightSideBearing = ttf->glyphs[t].xmax;
734 int width = ttf->glyphs[t].xmax - ttf->glyphs[t].xmin;
735 if(width > hea->xMaxExtent)
736 hea->xMaxExtent = width;
738 hea->caretSlopeRise = 1;
742 static int hea_parse(memreader_t*r, ttf_t*ttf)
744 table_hea_t*hea = ttf->hea = rfx_calloc(sizeof(table_hea_t));
745 U32 version = readU32(r);
746 ttf->ascent = readS16(r);
747 ttf->descent = readS16(r);
748 ttf->lineGap = readS16(r);
749 hea->advanceWidthMax = readU16(r);
750 hea->minLeftSideBearing = readS16(r);
751 hea->minRightSideBearing = readS16(r);
752 hea->xMaxExtent = readS16(r);
753 hea->caretSlopeRise = readS16(r);
754 hea->caretSlopeRun = readS16(r);
755 hea->caretOffset = readS16(r);
756 readS16(r); //reserved[0]
757 readS16(r); //reserved[1]
758 readS16(r); //reserved[2]
759 readS16(r); //reserved[3]
760 S16 metricDataFormat = readS16(r); //should be 0
761 if(metricDataFormat!=0) {
762 msg("<warning> Unknown metric format %d", metricDataFormat);
764 int num_advances = readU16(r);
765 if(num_advances > ttf->num_glyphs) {
766 msg("<warning> bad number of horizontal metrics: %d", num_advances);
767 num_advances = ttf->num_glyphs;
771 static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances)
773 table_hea_t*hea = ttf->hea;
774 writeU32(w, 0x00010000);
775 writeS16(w, ttf->ascent);
776 writeS16(w, ttf->descent);
777 writeS16(w, ttf->lineGap);
778 writeU16(w, hea->advanceWidthMax);
779 writeS16(w, hea->minLeftSideBearing);
780 writeS16(w, hea->minRightSideBearing);
781 writeS16(w, hea->xMaxExtent);
782 writeS16(w, hea->caretSlopeRise);
783 writeS16(w, hea->caretSlopeRun);
784 writeS16(w, hea->caretOffset);
785 writeS16(w, 0); //reserved
786 writeS16(w, 0); //reserved
787 writeS16(w, 0); //reserved
788 writeS16(w, 0); //reserved
789 writeS16(w, 0); //metricDataFormat
790 writeU16(w, num_advances);
793 static void hea_dump(ttf_t*ttf)
795 table_hea_t*hea = ttf->hea;
797 const char*dir = ttf->is_vertical?"v":"h";
798 printf("%shea->ascent: %d\n", dir, ttf->ascent);
799 printf("%shea->descent: %d\n", dir, ttf->descent);
800 printf("%shea->lineGap: %d\n", dir, ttf->lineGap);
801 printf("%shea->advanceWidthMax: %d\n", dir, hea->advanceWidthMax);
802 printf("%shea->minLeftSideBearing: %d\n", dir, hea->minLeftSideBearing);
803 printf("%shea->minRightSideBearing: %d\n", dir, hea->minRightSideBearing);
804 printf("%shea->xMaxExtent: %d\n", dir, hea->xMaxExtent);
805 printf("%shea->caretSlopeRise: %d\n", dir, hea->caretSlopeRise);
806 printf("%shea->caretSlopeRun: %d\n", dir, hea->caretSlopeRun);
807 printf("%shea->caretOffset: %d\n", dir, hea->caretOffset);
809 static void hea_delete(ttf_t*ttf)
817 static void mtx_parse(memreader_t*r, ttf_t*ttf, int num_advances)
821 if(num_advances > r->size/4)
822 num_advances = r->size/4;
823 for(t=0;t<num_advances;t++) {
824 old_advance = ttf->glyphs[t].advance = readU16(r);
825 ttf->glyphs[t].bearing = readS16(r);
827 int rest = (r->size - num_advances*4)/2;
828 if(ttf->num_glyphs < num_advances+rest) {
829 rest = ttf->num_glyphs-num_advances;
831 for(t=0;t<rest;t++) {
832 ttf->glyphs[t].advance = old_advance;
833 ttf->glyphs[t].bearing = readS16(r);
836 static int mtx_write(ttf_t*ttf, ttf_table_t*w)
838 int num_advances = ttf->num_glyphs;
839 if(ttf->num_glyphs>=2) {
841 for(t=ttf->num_glyphs-1;t>0;t--) {
842 if(ttf->glyphs[t-1].advance !=
843 ttf->glyphs[t].advance) break;
845 /* we need to store all individual advances as well
846 as one entry for the constant */
851 for(t=0;t<num_advances;t++) {
852 writeU16(w, ttf->glyphs[t].advance);
853 writeS16(w, ttf->glyphs[t].bearing);
855 for(;t<ttf->num_glyphs;t++) {
856 writeS16(w, ttf->glyphs[t].bearing);
861 static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size)
864 int num = ttf->num_glyphs+1;
865 U32*locations = rfx_calloc(num*sizeof(U32));
868 char warn_unsorted = 1;
870 if(num*4 > r->size) {
871 msg("<warning> Short 'loca' table (32 bit): %d/%d", r->size/4, num);
874 if(num*4 < r->size) {
875 msg("<warning> Extraneous data (%d bytes) in 'loca' table (32 bit)", r->size-num*4);
878 locations[t] = loc = readU32(r);
879 if(lastloc > loc && warn_unsorted) {
880 msg("<warning> Unsorted 'loca' table (32 bit)");
886 if(num*2 > r->size) {
887 msg("<warning> Short 'loca' table (16 bit)");
890 if(num*2 < r->size) {
891 msg("<warning> Extraneous data (%d bytes) in 'loca' table (16 bit)", r->size-num*2);
894 locations[t] = loc = readU16(r)*2;
895 if(lastloc > loc && warn_unsorted) {
896 msg("<warning> Unsorted 'loca' table");
904 static int loca_write(ttf_t*ttf, ttf_table_t*w, U32*locations)
908 for(t=0;t<=ttf->num_glyphs;t++) {
909 if(locations[t]>=0x20000 || (locations[t]&1)) {
916 for(t=0;t<=ttf->num_glyphs;t++) {
917 writeU32(w, locations[t]);
921 for(t=0;t<=ttf->num_glyphs;t++) {
922 writeU16(w, locations[t]/2);
928 static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int glyphnr)
930 ttfglyph_t*glyph = &ttf->glyphs[glyphnr];
934 endpoints = malloc(sizeof(U16)*num_contours);
937 for(s=0;s<num_contours;s++) {
938 int pos = endpoints[s] = readU16(r);
940 msg("<warning> Unsorted endpoints array (len:%d) last=%d now=%d", s, pos, lastpos);
945 U16 code_len = readU16(r);
947 glyph->code = malloc(sizeof(U16)*code_len);
948 readBlock(r, glyph->code, code_len);
949 glyph->code_size = code_len;
955 /*msg("<notice> TTF Glyph %d) code_size=%d num_contours=%d glyph->num_points=%d %d/%d/%d/%d",
956 glyphnr, code_len, num_contours, glyph->num_points,
957 xmin, ymin, xmax, ymax);*/
958 INIT_READ(fx, r->mem, r->size, r->pos);
959 INIT_READ(fy, r->mem, r->size, r->pos);
961 glyph->num_points = endpoints[num_contours-1] + 1;
962 glyph->points = rfx_calloc(sizeof(ttfpoint_t)*glyph->num_points);
964 /* parse flag array (1st pass- to determine start of coordinates) */
966 while(num<glyph->num_points) {
969 msg("<error> Bad flags in glyph outline: %02x (at pos %d)", flag, num);
972 glyph->num_points = 0;
978 if(count+num>glyph->num_points) {
979 msg("<warning> Bad count (%d) in glyph (%d) (at pos %d)", count, glyphnr, num);
980 count = glyph->num_points-num;
985 /* parse flag array (2nd pass) and x coordinates */
990 int bytepos = r->pos;
991 while(num<glyph->num_points) {
992 U8 flag = readU8(&fx);
993 int count = flag&8?readU8(&fx)+1:1;
994 count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
997 if(contour_pos<num_contours && num==endpoints[contour_pos]) {
1002 if((flag&0x12) == 0x12) x += readU8(r);
1003 else if((flag&0x12) == 0x02) x -= readU8(r);
1004 else if((flag&0x12) == 0x00) x += readS16(r);
1006 glyph->points[num].x = x;
1007 U8 f = flag&GLYPH_ON_CURVE;
1008 if(is_start) f|=GLYPH_CONTOUR_START;
1009 if(is_end) f|=GLYPH_CONTOUR_END;
1010 glyph->points[num].flags = f;
1016 /* parse flag array (3rd pass) and y coordinates */
1019 while(num<glyph->num_points) {
1020 U8 flag = readU8(&fy);
1021 int count = flag&8?readU8(&fy)+1:1;
1022 count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
1024 if((flag&0x24) == 0x24) y += readU8(r);
1025 else if((flag&0x24) == 0x04) y -= readU8(r);
1026 else if((flag&0x24) == 0x00) y += readS16(r);
1027 glyph->points[num].y = y;
1034 static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
1037 char warn_about_compound_glyphs=0;
1038 for(t=0;t<ttf->num_glyphs;t++) {
1039 INIT_READ(r, rr->mem, rr->size, loca[t]);
1040 if(loca[t]==loca[t+1] || loca[t]==r.size)
1041 continue; //empty glyph
1042 if(r.pos+10>r.size) {
1043 msg("<warning> Truncated glyph entry %d/%d (or bad loca entry %d/%d, next loca: %d)",
1044 t, ttf->num_glyphs, loca[t], r.size, loca[t+1]);
1047 S16 num_contours = readS16(&r);
1048 ttf->glyphs[t].xmin = readS16(&r);
1049 ttf->glyphs[t].ymin = readS16(&r);
1050 ttf->glyphs[t].xmax = readS16(&r);
1051 ttf->glyphs[t].ymax = readS16(&r);
1053 if(num_contours<0) {
1054 if(warn_about_compound_glyphs)
1055 msg("<error> Compound glyphs not supported yet");
1056 warn_about_compound_glyphs=0;
1058 if(!parse_simple_glyph(ttf, &r, num_contours, t))
1064 void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
1066 /* endpoints array */
1068 for(s=0;s<g->num_points;s++) {
1069 if(g->points[s].flags&GLYPH_CONTOUR_END)
1074 writeU16(w, g->code_size);
1076 writeBlock(w, g->code, g->code_size);
1083 for(s=0;s<g->num_points;s++) {
1084 ttfpoint_t*p = &g->points[s];
1085 int dx = p->x - lastx;
1086 int dy = p->y - lasty;
1087 U8 flags = p->flags&GLYPH_ON_CURVE;
1090 } else if(dx<0 && dx>=-255) {
1092 } else if(dx>0 && dx<=255) {
1097 } else if(dy<0 && dy>=-255) {
1099 } else if(dy>0 && dy<=255) {
1102 if(flags == lastflag && flagcount<255) {
1107 writeU8(w, lastflag|8);
1108 writeU8(w, flagcount);
1110 writeU8(w, lastflag);
1121 writeU8(w, lastflag|8);
1122 writeU8(w, flagcount);
1124 writeU8(w, lastflag);
1129 int bytepos = w->len;
1130 for(s=0;s<g->num_points;s++) {
1131 ttfpoint_t*p = &g->points[s];
1132 int dx = p->x - lastx;
1133 if(dx>32767 || dx<-32768) {
1134 msg("<error> Coordinate overflow in glyph");
1137 if(dx>0 && dx<=255) writeU8(w, dx);
1138 else if(dx<0 && dx>=-255) writeU8(w, -dx);
1139 else if(dx) writeS16(w, dx);
1143 for(s=0;s<g->num_points;s++) {
1144 ttfpoint_t*p = &g->points[s];
1145 int dy = p->y - lasty;
1146 if(dy>32767 || dy<-32768) {
1147 msg("<error> Coordinate overflow in glyph");
1150 if(dy>0 && dy<=255) writeU8(w, dy);
1151 else if(dy<0 && dy>=-255) writeU8(w, -dy);
1152 else if(dy) writeS16(w, dy);
1155 U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
1157 U32*locations = malloc(sizeof(U32)*(ttf->num_glyphs+1));
1159 for(t=0;t<ttf->num_glyphs;t++) {
1160 locations[t] = w->len;
1161 ttfglyph_t*g = &ttf->glyphs[t];
1163 int num_contours = 0;
1164 for(s=0;s<g->num_points;s++) {
1165 if(g->points[s].flags&GLYPH_CONTOUR_END)
1168 writeS16(w, num_contours?num_contours:1);
1169 writeS16(w, g->xmin);
1170 writeS16(w, g->ymin);
1171 writeS16(w, g->xmax);
1172 writeS16(w, g->ymax);
1175 /* some ttf parsers can't deal with zero contours, so in the case
1176 of an empty glyph, write a single point (0,0) */
1177 writeU16(w, 0); //endpoint of 1st contour
1178 writeU16(w, g->code_size);
1180 writeBlock(w, g->code, g->code_size);
1181 writeU8(w, 0x31); //flag (xy=(0,0),on curve)
1183 write_simple_glyph(w, g);
1186 locations[t] = w->len;
1189 void glyf_dump(ttf_t* ttf)
1191 if(!ttf->glyphs) return;
1193 for(t=0;t<ttf->num_glyphs;t++) {
1194 ttfglyph_t*g = &ttf->glyphs[t];
1195 printf("glyph %d)\n", t);
1196 printf(" advance=%d\n", g->advance);
1197 printf(" bearing=%d\n", g->bearing);
1198 printf(" bbox=(%d/%d/%d/%d)\n", g->xmin, g->ymin, g->xmax, g->ymax);
1199 printf(" points=(");
1201 for(s=0;s<g->num_points;s++) {
1203 printf("%d/%d/0x%02x", g->points[s].x, g->points[s].y, g->points[s].flags);
1207 hexdump(g->code, g->code_size, " ");
1210 void glyf_delete(ttf_t* ttf)
1215 for(t=0;t<ttf->num_glyphs;t++) {
1216 if(ttf->glyphs[t].code) {
1217 free(ttf->glyphs[t].code);
1218 ttf->glyphs[t].code = 0;
1220 if(ttf->glyphs[t].points) {
1221 free(ttf->glyphs[t].points);
1222 ttf->glyphs[t].points = 0;
1225 free(ttf->glyphs);ttf->glyphs=0;
1228 static void grow_unicode(ttf_t*ttf, int index)
1232 ttf->unicode = rfx_calloc(sizeof(ttf->unicode[0])*size);
1233 } else if(ttf->unicode_size<size) {
1234 ttf->unicode = rfx_realloc(ttf->unicode, sizeof(ttf->unicode[0])*size);
1235 memset(ttf->unicode+ttf->unicode_size, 0, sizeof(ttf->unicode[0])*(size - ttf->unicode_size));
1237 ttf->unicode_size = size;
1239 void cmap_parse(memreader_t*r, ttf_t*ttf)
1241 readU16(r); // version (0)
1242 int num_subtables = readU16(r);
1245 if(r->pos+num_subtables*8 > r->size) {
1246 msg("<warning> CMap overflow");
1247 num_subtables = (r->size-r->pos)/8;
1250 for(t=0;t<num_subtables;t++) {
1251 U16 platform = readU16(r);
1252 U16 encoding = readU16(r);
1253 U32 offset = readU32(r);
1254 if(offset>r->size) {
1255 msg("<warning> CMAP table %d %d is out of bounds (%d)", platform, encoding, offset);
1259 int is_unicode = platform==0 ||
1260 platform==3 && encoding == 1 ||
1261 platform==3 && encoding == 10;
1266 INIT_READ(t, r->mem, r->size, offset);
1267 U16 format = readU16(&t);
1268 int length = readU16(&t);
1269 U16 language = readU16(&t);
1272 msg("<warning> Language code %02x in unicode mapping", language);
1277 if(t.pos+length > t.size) {
1278 msg("<warning> overflow in format 0 cmap table");
1281 data = malloc(num*sizeof(unicode_t));
1283 grow_unicode(ttf, num);
1284 for(s=0;s<num;s++) {
1285 ttf->unicode[s] = readU8(&t);
1287 } else if(format == 4) {
1288 U16 segment_count = readU16(&t);
1289 if(segment_count&1) {
1290 msg("<error> Bad segmentx2 count %d", segment_count);
1294 readU16(&t); //searchrange
1295 readU16(&t); //entry selector
1296 readU16(&t); //range shift
1297 INIT_READ(r_end, t.mem, t.size, t.pos);
1298 INIT_READ(r_start, t.mem, t.size, t.pos+2+segment_count*2);
1299 INIT_READ(r_delta, t.mem, t.size, t.pos+2+segment_count*4);
1300 INIT_READ(r_range, t.mem, t.size, t.pos+2+segment_count*6);
1301 int glyphmap_start = t.pos+2+segment_count*8;
1302 int glyphmap_size = t.size - glyphmap_start;
1304 for(s=0;s<segment_count;s++) {
1305 U16 start = readU16(&r_start);
1306 U16 end = readU16(&r_end);
1307 U16 delta = readU16(&r_delta);
1308 U16 range = readU16(&r_range);
1309 if(start==0xffff && end==0xffff && delta==1) {
1310 /* this is a common (maybe even required) occurence in fonts
1311 which explicitly map "unicode undefined" (0xffff) to
1312 "glyph undefined" (0).
1313 We don't want to blow our unicode table up to 65536 just
1314 because of this, so ignore this entry.
1318 grow_unicode(ttf, end);
1321 for(u=start;u<=end;u++) {
1322 ttf->unicode[u] = (u + delta) & 0xffff;
1325 int pos = r_range.pos-2+range;
1326 if(warn && pos+end-start+1 > t.size) {
1327 msg("<warning> glyphmap index out of bounds (%d-%d/%d)", pos, pos+end-start, t.size);
1330 INIT_READ(g, t.mem, t.size, pos);
1331 for(u=start;u<=end;u++) {
1332 ttf->unicode[u] = readU16(&g);
1339 static int segment_size(unicode_t*unicode, int pos, int size)
1343 for(s=pos;s<size;s++) {
1347 /* a segment costs us 8 bytes, so for more than 4 consecutive
1348 zero entries (16 bit each) in the glyph index array,
1349 it pays off to start a new segment */
1353 s -= count; // go to the last filled in entry
1358 void cmap_write(ttf_t* ttf, ttf_table_t*w)
1360 writeU16(w, 0); //version
1361 writeU16(w, 2); //two tables
1363 writeU16(w, 0); //platform (unicode)
1364 writeU16(w, 3); //encoding (unicode 2.0)
1365 writeU32(w, 20); //offset
1367 writeU16(w, 3); //platform (windows)
1368 writeU16(w, 1); //encoding (unicode basic multilingual plane UCS-2)
1369 writeU32(w, 20); //offset
1371 writeU16(w, 4); // format=4
1372 int length_pos = w->len;
1373 writeU16(w, 0); // length: we don't know yet
1374 writeU16(w, 0); // language (n/a for unicode)
1375 int num_segments_pos = w->len;
1376 writeU16(w, 0); //number of segments: we don't know yet either
1377 writeU16(w, 0); //searchrange
1378 writeU16(w, 0); //entry selector
1379 writeU16(w, 0); //range shift
1383 while(pos < ttf->unicode_size) {
1384 if(!ttf->unicode[pos]) {
1388 int s = segment_size(ttf->unicode, pos, ttf->unicode_size);
1393 num_segments++; // account for 0xffff mapping
1395 int glyphmap_start = w->len+2+num_segments*8;
1398 int end_pos = w->len;
1399 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
1400 writeU16(w, 0); //reserved byte
1401 int start_pos = w->len;
1402 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //start array
1403 int delta_pos = w->len;
1404 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //delta array
1405 int range_pos = w->len;
1406 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //range array
1408 /* backpatch number of segments */
1409 w->data[num_segments_pos++]=(num_segments*2)>>8;
1410 w->data[num_segments_pos++]=(num_segments*2);
1411 /* backpatch search range */
1412 int tmp = num_segments;
1413 int search_range = 0;
1418 w->data[num_segments_pos++]=(search_range*2)>>8;
1419 w->data[num_segments_pos++]=(search_range*2);
1420 /* backpatch entry selector */
1421 int entry_selector = 0;
1423 while(tmp>1) {tmp>>=1;entry_selector++;}
1424 w->data[num_segments_pos++]=entry_selector>>8;
1425 w->data[num_segments_pos++]=entry_selector;
1426 /* backpatch range shift */
1427 int range_shift = num_segments*2 - search_range*2;
1428 w->data[num_segments_pos++]=range_shift>>8;
1429 w->data[num_segments_pos++]=range_shift;
1433 while(pos < ttf->unicode_size) {
1434 if(!ttf->unicode[pos]) {
1438 U16 end = segment_size(ttf->unicode, pos, ttf->unicode_size);
1439 w->data[end_pos++]=end>>8;
1440 w->data[end_pos++]=end;
1441 w->data[start_pos++]=pos>>8;
1442 w->data[start_pos++]=pos;
1444 U16 delta = ttf->unicode[pos]-pos;
1446 for(s=pos+1;s<=end;s++) {
1447 U16 delta2 = ttf->unicode[s]-s;
1458 range = w->len - range_pos;
1459 for(s=pos;s<=end;s++) {
1460 writeU16(w, ttf->unicode[s]);
1463 w->data[delta_pos++]=delta>>8;
1464 w->data[delta_pos++]=delta;
1465 w->data[range_pos++]=range>>8;
1466 w->data[range_pos++]=range;
1471 /* write out a mapping from 0xffff to 0- seems to be required
1472 by some libraries (e.g. fonttools) */
1473 w->data[end_pos++]=0xff;
1474 w->data[end_pos++]=0xff;
1475 w->data[start_pos++]=0xff;
1476 w->data[start_pos++]=0xff;
1477 w->data[delta_pos++]=0;
1478 w->data[delta_pos++]=1;
1479 w->data[range_pos++]=0;
1480 w->data[range_pos++]=0;
1482 w->data[length_pos]=(w->len-20)>>8;
1483 w->data[length_pos+1]=w->len-20;
1485 void cmap_delete(ttf_t*ttf)
1491 ttf->unicode_size=0;
1493 static char*readString(memreader_t*r, int len)
1495 char*s = malloc(len+1);
1496 readBlock(r, s, len);
1500 void name_parse(memreader_t*r, ttf_t*ttf)
1502 U16 format = readU16(r);
1503 U16 count = readU16(r);
1504 U16 offset = readU16(r);
1507 for(t=0;t<count;t++) {
1508 U16 platform = readU16(r);
1509 U16 encoding = readU16(r);
1510 U16 language = readU16(r);
1511 U16 name_id = readU16(r);
1512 U16 len = readU16(r);
1513 U16 offset_2 = readU16(r);
1515 char ** read_name = 0;
1517 INIT_READ(ss, r->mem, r->size, offset+offset_2);
1518 if(!(platform==0 || (platform==1 && encoding==0)))
1521 INIT_READ(s, r->mem, r->size, offset+offset_2);
1524 case 1: read_name = &ttf->family_name; break;
1525 case 2: read_name = &ttf->subfamily_name; break;
1526 case 3: read_name = &ttf->font_uid; break;
1527 case 4: read_name = &ttf->full_name; break;
1528 case 5: read_name = &ttf->version_string; break;
1529 case 6: read_name = &ttf->postscript_name; break;
1530 default: read_name = 0;
1534 if (*read_name) free(*read_name);
1535 *read_name = readString(&s, len);
1539 void name_write(ttf_t*ttf, ttf_table_t*table)
1541 char*strings[6] = {ttf->family_name, ttf->subfamily_name, ttf->font_uid, ttf->full_name, ttf->version_string, ttf->postscript_name};
1542 int codes[6] = {1,2,3,4,5,6};
1544 writeU16(table, 0); //format
1547 int nr = sizeof(strings)/sizeof(strings[0]);
1553 writeU16(table, count); //count
1555 int offset_pos = table->len;
1556 writeU16(table, 0); //offset (will be filled in later)
1558 /* Windows expects the name table to be sorted by platform/encoding/language/name_id */
1562 writeU16(table, 1); //platform id (mac)
1563 writeU16(table, 0); //encoding id (latin-1)
1564 writeU16(table, 0); //language (english)
1565 writeU16(table, codes[t]);
1566 int len = strlen(strings[t]);
1567 writeU16(table, len);
1568 writeU16(table, offset);
1574 writeU16(table, 3); //platform id (windows)
1575 writeU16(table, 1); //encoding id (ucs-2)
1576 writeU16(table, 0x409); //language (US)
1577 writeU16(table, codes[t]);
1578 int len2 = strlen(strings[t]) * 2;
1579 writeU16(table, len2);
1580 writeU16(table, offset);
1585 table->data[offset_pos] = table->len>>8;
1586 table->data[offset_pos+1] = table->len;
1590 int len = strlen(strings[t]);
1591 writeBlock(table, strings[t], len);
1597 int len = strlen(strings[t]);
1598 for(s=0;s<len;s++) {
1600 writeU8(table, strings[t][s]);
1605 void name_delete(ttf_t*ttf)
1607 if(ttf->full_name) {
1608 free(ttf->full_name);
1611 if(ttf->family_name) {
1612 free(ttf->family_name);
1615 if(ttf->subfamily_name) {
1616 free(ttf->subfamily_name);
1617 ttf->subfamily_name=0;
1619 if(ttf->version_string) {
1620 free(ttf->version_string);
1621 ttf->version_string=0;
1624 free(ttf->font_uid);
1627 if(ttf->postscript_name) {
1628 free(ttf->postscript_name);
1629 ttf->postscript_name=0;
1633 static table_post_t*post_new(ttf_t*ttf)
1635 table_post_t*post = rfx_calloc(sizeof(table_post_t));
1638 void post_parse(memreader_t*r, ttf_t*ttf)
1640 table_post_t*post = ttf->post = rfx_calloc(sizeof(table_post_t));
1641 U32 format = readU32(r);
1642 post->italic_angle = readU32(r);
1643 post->underline_position = readU16(r);
1644 post->underline_thickness = readU16(r);
1645 U16 is_monospaced = readU32(r);
1646 readU32(r); // min mem 42
1648 readU32(r); // min mem 1
1651 void post_write(ttf_t*ttf, ttf_table_t*table)
1653 table_post_t*post = ttf->post;
1654 writeU32(table, 0x00030000);
1655 writeU32(table, post->italic_angle);
1656 writeU16(table, post->underline_position);
1657 writeU16(table, post->underline_thickness);
1658 writeU32(table, 0); //is monospaced TODO
1659 writeU32(table, 0); //min mem 42
1661 writeU32(table, 0); //min mem 1
1664 void post_delete(ttf_t*ttf)
1672 void cvt_parse(memreader_t*r, ttf_t*ttf)
1674 table_cvt_t*cvt = ttf->cvt = rfx_calloc(sizeof(table_cvt_t));
1675 cvt->num = r->size/2;
1676 cvt->values = malloc(cvt->num*sizeof(S16));
1678 for(t=0;t<cvt->num;t++) {
1679 cvt->values[t] = readS16(r);
1682 void cvt_write(ttf_t*ttf, ttf_table_t*table)
1684 table_cvt_t*cvt = ttf->cvt;
1686 for(t=0;t<cvt->num;t++) {
1687 writeS16(table, cvt->values[t]);
1690 void cvt_delete(ttf_t*ttf)
1693 if(ttf->cvt->values)
1694 free(ttf->cvt->values);
1700 static table_gasp_t*gasp_new(ttf_t*ttf)
1702 table_gasp_t*gasp = rfx_calloc(sizeof(table_gasp_t));
1704 gasp->records = rfx_calloc(sizeof(gasp->records[0])*gasp->num);
1706 gasp->records[0].size = 65535;
1707 gasp->records[0].behaviour = 15; //gridfit+grayscale rendering
1710 void gasp_parse(memreader_t*r, ttf_t*ttf)
1712 table_gasp_t*gasp = ttf->gasp = rfx_calloc(sizeof(table_gasp_t));
1713 readU16(r); //version
1714 int num = readU16(r);
1717 gasp->records = malloc(sizeof(gasp->records[0])*num);
1718 for(t=0;t<num;t++) {
1719 gasp->records[t].size = readU16(r);
1720 gasp->records[t].behaviour = readU16(r);
1724 #define GASP_SYMMETRIC_GRIDFIT 0x0008
1725 #define GASP_SYMMETRIC_SMOOTHING 0x0004
1726 #define GASP_DOGRAY 0x0002
1727 #define GASP_GRIDFIT 0x0001
1729 void gasp_write(ttf_t*ttf, ttf_table_t*table)
1731 table_gasp_t*gasp = ttf->gasp;
1734 for(t=0;t<gasp->num;t++) {
1735 if(gasp->records[t].behaviour & ~(GASP_GRIDFIT | GASP_DOGRAY)) {
1739 writeU16(table, version);
1740 writeU16(table, gasp->num);
1741 for(t=0;t<gasp->num;t++) {
1742 writeU16(table, gasp->records[t].size);
1743 writeU16(table, gasp->records[t].behaviour);
1746 void gasp_delete(ttf_t*ttf)
1749 if(ttf->gasp->records)
1750 free(ttf->gasp->records);
1756 table_code_t*prep_new(ttf_t*ttf)
1758 table_code_t*prep = ttf->prep = rfx_calloc(sizeof(table_code_t));
1759 ttf_table_t*t = ttf_table_new(0);
1760 writeU8(t,0xb8);writeU16(t,0x1ff); // pushword(0x1ff)
1761 writeU8(t,0x85); //scanctrl (always do dropout, for all sizes)
1762 writeU8(t,0xb0);writeU8(t,1); // pushbyte(1)
1763 writeU8(t,0x8d); //scantype (simple dropout control w/o stubs)
1764 writeU8(t,0xb0);writeU8(t,5); // pushbyte(5)
1765 writeU8(t,0x8d); //scantype (for windows) smart dropout control w/o stubs
1766 prep->code = t->data;
1767 prep->size = t->len;
1772 void fpgm_parse(memreader_t*r, ttf_t*ttf)
1774 table_code_t*fpgm = ttf->fpgm = rfx_calloc(sizeof(table_code_t));
1775 if(!r->size) return;
1776 fpgm->size = r->size;
1777 fpgm->code = malloc(r->size);
1778 readBlock(r, fpgm->code, r->size);
1780 void fpgm_write(ttf_t*ttf, ttf_table_t*table)
1782 table_code_t*code = ttf->fpgm;
1783 writeBlock(table, code->code, code->size);
1785 void fpgm_delete(ttf_t*ttf)
1789 free(ttf->fpgm->code);
1795 void prep_parse(memreader_t*r, ttf_t*ttf)
1797 table_code_t*prep = ttf->prep = rfx_calloc(sizeof(table_code_t));
1798 if(!r->size) return;
1799 prep->size = r->size;
1800 prep->code = malloc(r->size);
1801 readBlock(r, prep->code, r->size);
1803 void prep_write(ttf_t*ttf, ttf_table_t*table)
1805 table_code_t*code = ttf->prep;
1806 writeBlock(table, code->code, code->size);
1808 void prep_delete(ttf_t*ttf)
1812 free(ttf->prep->code);
1818 static int ttf_parse_tables(ttf_t*ttf)
1822 table = ttf_find_table(ttf, TAG_HEAD);
1824 msg("<error> Font has no head table");
1827 INIT_READ(m, table->data, table->len, 0);
1828 int loc_index = head_parse(ttf, &m);
1829 ttf_table_delete(ttf, table);
1831 table = ttf_find_table(ttf, TAG_MAXP);
1833 msg("<error> Font has no maxp table");
1836 INIT_READ(m2, table->data, table->len, 0);
1837 ttf->maxp = maxp_parse(ttf, &m2);
1838 ttf_table_delete(ttf, table);
1840 if(!ttf->num_glyphs) {
1841 msg("<error> Invalid number of characters");
1844 ttf->glyphs = rfx_calloc(sizeof(ttfglyph_t)*ttf->num_glyphs);
1846 table = ttf_find_table(ttf, TAG_OS2);
1848 INIT_READ(m, table->data, table->len, 0);
1849 ttf->os2 = os2_parse(&m);
1850 ttf_table_delete(ttf, table);
1854 table = ttf_find_table(ttf, TAG_HHEA);
1856 INIT_READ(m, table->data, table->len, 0);
1857 int num_advances = hea_parse(&m, ttf);
1858 ttf_table_delete(ttf, table);
1860 table = ttf_find_table(ttf, TAG_HMTX);
1862 INIT_READ(m, table->data, table->len, 0);
1863 mtx_parse(&m, ttf, num_advances);
1864 ttf_table_delete(ttf, table);
1867 table = ttf_find_table(ttf, TAG_VHEA);
1870 INIT_READ(m, table->data, table->len, 0);
1871 int num_advances = hea_parse(&m, ttf);
1872 ttf_table_delete(ttf, table);
1874 table = ttf_find_table(ttf, TAG_VMTX);
1876 INIT_READ(m, table->data, table->len, 0);
1877 mtx_parse(&m, ttf, num_advances);
1878 ttf_table_delete(ttf, table);
1881 msg("<error> Font contains neither HHEA nor VHEA");
1884 table = ttf_find_table(ttf, TAG_LOCA);
1886 INIT_READ(m, table->data, table->len, 0);
1887 U32*loca = loca_parse(&m, ttf, loc_index);
1888 ttf_table_delete(ttf, table);
1889 table = ttf_find_table(ttf, TAG_GLYF);
1891 INIT_READ(m, table->data, table->len, 0);
1892 glyf_parse(&m, ttf, loca);
1893 ttf_table_delete(ttf, table);
1898 table = ttf_find_table(ttf, TAG_CMAP);
1900 INIT_READ(m, table->data, table->len, 0);
1901 cmap_parse(&m, ttf);
1902 ttf_table_delete(ttf, table);
1905 table = ttf_find_table(ttf, TAG_POST);
1907 INIT_READ(m, table->data, table->len, 0);
1908 post_parse(&m, ttf);
1909 ttf_table_delete(ttf, table);
1912 table = ttf_find_table(ttf, TAG_NAME);
1914 INIT_READ(m, table->data, table->len, 0);
1915 name_parse(&m, ttf);
1916 ttf_table_delete(ttf, table);
1919 table = ttf_find_table(ttf, TAG_CVT);
1921 INIT_READ(m, table->data, table->len, 0);
1923 ttf_table_delete(ttf, table);
1926 table = ttf_find_table(ttf, TAG_GASP);
1928 INIT_READ(m, table->data, table->len, 0);
1929 gasp_parse(&m, ttf);
1930 ttf_table_delete(ttf, table);
1933 table = ttf_find_table(ttf, TAG_PREP);
1935 INIT_READ(m, table->data, table->len, 0);
1936 prep_parse(&m, ttf);
1937 ttf_table_delete(ttf, table);
1940 table = ttf_find_table(ttf, TAG_FPGM);
1942 INIT_READ(m, table->data, table->len, 0);
1943 fpgm_parse(&m, ttf);
1944 ttf_table_delete(ttf, table);
1949 static void ttf_collapse_tables(ttf_t*ttf)
1953 ttf_table_t*head = ttf_find_table(ttf, TAG_HEAD);
1955 return; //already collapsed
1958 table = ttf_addtable(ttf, TAG_MAXP);
1959 maxp_write(ttf, table);
1964 table = ttf_addtable(ttf, TAG_OS2);
1965 os2_write(ttf, table);
1970 if(!ttf->is_vertical) {
1971 table = ttf_addtable(ttf, TAG_HMTX);
1972 int num_advances = mtx_write(ttf, table);
1973 table = ttf_addtable(ttf, TAG_HHEA);
1974 hea_write(ttf, table, num_advances);
1977 table = ttf_addtable(ttf, TAG_VMTX);
1978 int num_advances = mtx_write(ttf, table);
1979 table = ttf_addtable(ttf, TAG_VHEA);
1980 hea_write(ttf, table, num_advances);
1986 if(ttf->num_glyphs) {
1988 table = ttf_addtable(ttf, TAG_CMAP);
1989 cmap_write(ttf, table);
1994 table = ttf_addtable(ttf, TAG_GLYF);
1995 U32*locations = glyf_write(ttf, table);
1996 table = ttf_addtable(ttf, TAG_LOCA);
1997 loca_size = loca_write(ttf, table, locations);
2003 if(ttf->full_name || ttf->family_name || ttf->subfamily_name || ttf->font_uid || ttf->postscript_name) {
2004 table = ttf_addtable(ttf, TAG_NAME);
2005 name_write(ttf, table);
2009 table = ttf_addtable(ttf, TAG_POST);
2010 post_write(ttf, table);
2014 table = ttf_addtable(ttf, TAG_CVT);
2015 cvt_write(ttf, table);
2019 table = ttf_addtable(ttf, TAG_GASP);
2020 gasp_write(ttf, table);
2024 table = ttf_addtable(ttf, TAG_FPGM);
2025 fpgm_write(ttf, table);
2029 table = ttf_addtable(ttf, TAG_PREP);
2030 prep_write(ttf, table);
2034 table = ttf_addtable(ttf, TAG_HEAD);
2035 head_write(ttf, table, loca_size);
2041 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
2042 ttf->version = VERSION_1_0;
2045 ttf_t* ttf_load(void*data, int length)
2047 INIT_READ(r,data,length, 0);
2050 msg("<error> Truncated Truetype file (%d bytes)", length);
2054 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
2055 ttf->version = readU32(&r);
2056 if(ttf->version == SWAP32(length)) {
2057 U32 fontDataSize = readU32(&r);
2058 U32 version = readU32(&r);
2059 U32 flags = readU32(&r);
2061 readBlock(&r, panose, 10);
2062 readU8(&r); //charset
2063 readU8(&r); //italoc
2064 readU32(&r); //weight
2065 readU16(&r); //fstype
2066 U16 magic = readU16(&r); //magicNumber
2067 /* we're being paranoid: it's entirely possible for the font
2068 size to be exactly 0x10000. Only treat this font as eot if
2069 it has the right magic number */
2070 if(magic == 0x4c50) {
2071 readU32(&r); //unicoderange[0]
2072 readU32(&r); //unicoderange[1]
2073 readU32(&r); //unicoderange[2]
2074 readU32(&r); //unicoderange[3]
2075 readU32(&r); //codepagerange[0]
2076 readU32(&r); //codepagerange[1]
2077 readU32(&r); //checksumadjustment
2078 readU32(&r); //reserved[0]
2079 readU32(&r); //reserved[1]
2080 readU32(&r); //reserved[2]
2081 readU32(&r); //reserved[3]
2082 readU16(&r); //padding
2085 for(nr=0;nr<4;nr++) {
2087 /* All of ttf is big-endian. All of ttf? No. One small eot table
2088 of indomitable little-endian... */
2090 len |= readU8(&r)<<8;
2092 for(t=0;t<len;t++) {
2093 U8 c = readU16(&r)>>8;
2095 readU16(&r); // zero terminator
2097 readU16(&r); // more padding
2099 /* adjust the offset to the start of the actual truetype
2100 data- the positions in the table header will be relative
2101 to the ttf data after the header, not to the file */
2105 ttf->version = readU32(&r);
2108 ttf->version = readU32(&r);
2112 if(ttf->version == TTCFTAG) {
2113 /* a ttc collection is a number of truetype fonts
2114 packaged together */
2116 msg("<error> Truncated TTC file (%d bytes)", length);
2119 U32 ttcf_version = readU32(&r); // 0x00000100: v1.0, 0x00000200: v2.0, includes DSIG table
2120 U32 num_fonts = readU32(&r); // number of fonts
2121 U32 font1_position = readU32(&r);
2122 if(font1_position+12 > length) {\
2123 msg("<error> Truncated TTC file (%d bytes, first font at %d)", length, font1_position);
2126 r.pos = font1_position;
2127 ttf->version = readU32(&r);
2130 int num_tables = readU16(&r);
2132 readU16(&r); //search range
2133 readU16(&r); //entry selector
2134 readU16(&r); //range shift
2136 if(num_tables*16 > length) {
2137 msg("<error> Truncated TTF file (table entries: %d)", num_tables);
2138 if(ttf->version != OPENTYPE &&
2139 ttf->version != TRUETYPE_MACOS &&
2140 ttf->version != VERSION_1_0) {
2141 // bad table length, weird version. This is probably not a ttf file.
2146 U32*table_data = malloc(16*num_tables);
2148 for(t=0;t<num_tables*4;t++) {
2149 table_data[t] = readU32(&r);
2151 for(t=0;t<num_tables;t++) {
2152 U32 tag = table_data[t*4];
2153 U32 checksum = table_data[t*4+1];
2154 U32 pos = table_data[t*4+2];
2155 U32 len = table_data[t*4+3];
2157 if(pos+len > length) {
2158 msg("<error> TTF Table %02x%02x%02x%02x outside of stream (pos %d)", (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, pos);
2160 U8*mem = malloc(len);
2162 readBlock(&r, mem, len);
2164 ttf_table_t*table = ttf_addtable(ttf, tag);
2166 table->len = table->memsize = len;
2168 U32 checksum2 = ttf_table_checksum(table);
2169 if(checksum2!=checksum) {
2170 msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x",
2171 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
2172 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
2173 len, checksum2, checksum);
2180 if(!ttf_parse_tables(ttf))
2185 void ttf_create_truetype_tables(ttf_t*ttf)
2188 ttf->head = head_new(ttf);
2190 ttf->maxp = maxp_new(ttf);
2192 ttf->hea = hea_new(ttf);
2194 ttf->os2 = os2_new(ttf);
2196 ttf->post = post_new(ttf);
2198 ttf->gasp = gasp_new(ttf);
2200 ttf->prep = prep_new(ttf);
2203 ttf_table_t* ttf_write(ttf_t*ttf, U32*checksum_adjust)
2205 ttf_collapse_tables(ttf);
2207 ttf_table_t*file = ttf_table_new(0);
2208 writeU32(file, VERSION_1_0);
2210 /* write number of tables */
2212 ttf_table_t*t = ttf->tables;
2217 writeU16(file, num_tables);
2219 /* write search range */
2220 int tmp = num_tables;
2221 int search_range = 0;
2228 writeU16(file, search_range);
2230 /* write entry selector */
2231 int entry_selector = 0;
2236 writeU16(file, entry_selector);
2238 /* write range shift */
2239 int range_shift = num_tables*16 - search_range;
2240 writeU16(file, range_shift);
2242 /* write table dictionary */
2243 int table_dictionary_pos = file->len;
2244 int data_pos = file->len + num_tables*16;
2245 for(t=ttf->tables;t;t=t->next) {
2246 writeU32(file, t->id);
2247 writeU32(file, ttf_table_checksum(t));
2248 writeU32(file, data_pos);
2249 writeU32(file, t->len);
2251 data_pos += (-t->len)&3; //pad
2256 U8 zero[4]={0,0,0,0};
2257 for(t=ttf->tables;t;t=t->next) {
2258 if(t->id == TAG_HEAD)
2259 head_pos = file->len;
2260 writeBlock(file, t->data, t->len);
2261 writeBlock(file, zero, (-t->len)&3); //pad
2263 U32 checksum = 0xb1b0afba - ttf_table_checksum(file);
2265 *checksum_adjust = checksum;
2266 U8*checksum2 = file->data + head_pos + 8;
2267 checksum2[0] = checksum>>24;
2268 checksum2[1] = checksum>>16;
2269 checksum2[2] = checksum>>8;
2270 checksum2[3] = checksum>>0;
2274 ttf_table_t* ttf_eot_head(ttf_t*ttf)
2276 ttf_table_t*file = ttf_table_new(0);
2277 writeU32(file, 0); //file size (filled in later)
2278 writeU32(file, 0); //fontdatasize (filled in later)
2279 writeU32(file, 0x01000200);
2280 writeU32(file, 0); //flags
2281 writeU8(file, ttf->os2->panose_FamilyType);
2282 writeU8(file, ttf->os2->panose_SerifStyle);
2283 writeU8(file, ttf->os2->panose_Weight);
2284 writeU8(file, ttf->os2->panose_Proportion);
2285 writeU8(file, ttf->os2->panose_Contrast);
2286 writeU8(file, ttf->os2->panose_StrokeVariation);
2287 writeU8(file, ttf->os2->panose_ArmStyle);
2288 writeU8(file, ttf->os2->panose_Letterform);
2289 writeU8(file, ttf->os2->panose_Midline);
2290 writeU8(file, ttf->os2->panose_XHeight);
2291 writeU8(file, 1); //charset (default)
2292 writeU8(file, ttf->os2->fsSelection&1); //italic
2293 writeU32_LE(file, ttf->os2->usWeightClass);
2294 writeU16(file, 0); //fstype
2295 writeU16(file, 0x4c50); //magic
2296 writeU32_LE(file, ttf->os2->ulCharRange[0]);
2297 writeU32_LE(file, ttf->os2->ulCharRange[1]);
2298 writeU32_LE(file, ttf->os2->ulCharRange[2]);
2299 writeU32_LE(file, ttf->os2->ulCharRange[3]);
2300 writeU32_LE(file, ttf->os2->ulCodePageRange1);
2301 writeU32_LE(file, ttf->os2->ulCodePageRange2);
2302 writeU32(file, 0); //checksum adjust (filled in later)
2303 writeU32(file, 0); //reserved[0]
2304 writeU32(file, 0); //reserved[1]
2305 writeU32(file, 0); //reserved[2]
2306 writeU32(file, 0); //reserved[3]
2307 writeU16(file, 0); //padding(1)
2311 char* strings[] = {ttf->family_name, ttf->subfamily_name, ttf->version_string, ttf->full_name};
2312 int nr = sizeof(strings)/sizeof(strings[0]);
2315 char *string = strings[i];
2318 len = strlen(string);
2319 writeU16_LE(file, len*2);
2320 for(t=0;t<len;t++) {
2322 writeU8(file, string[t]);
2324 writeU16(file, 0); //zero byte pad
2327 writeU16(file, 0); //zero byte pad
2329 writeU16(file, 0); //padding(2)
2333 void ttf_save_eot(ttf_t*ttf, const char*filename)
2335 ttf_table_t* eot = ttf_eot_head(ttf);
2336 U32 checksum_adjust = 0;
2337 ttf_table_t* t = ttf_write(ttf, &checksum_adjust);
2339 U8*len_data = eot->data;
2340 U32 full_len = eot->len + t->len;
2341 len_data[0] = full_len>>0;
2342 len_data[1] = full_len>>8;
2343 len_data[2] = full_len>>16;
2344 len_data[3] = full_len>>24;
2346 U8*len_data2 = eot->data+4;
2347 len_data2[0] = t->len>>0;
2348 len_data2[1] = t->len>>8;
2349 len_data2[2] = t->len>>16;
2350 len_data2[3] = t->len>>24;
2352 U8*checksum_data = eot->data + 60;
2353 checksum_data[0] = checksum_adjust>>0;
2354 checksum_data[1] = checksum_adjust>>8;
2355 checksum_data[2] = checksum_adjust>>16;
2356 checksum_data[3] = checksum_adjust>>24;
2358 FILE*fi = fopen(filename, "wb");
2364 fwrite(eot->data, eot->len, 1, fi);
2365 fwrite(t->data, t->len, 1, fi);
2367 ttf_table_delete(0, t);
2368 ttf_table_delete(0, eot);
2371 void ttf_save(ttf_t*ttf, const char*filename)
2373 ttf_table_t* t = ttf_write(ttf, 0);
2374 FILE*fi = fopen(filename, "wb");
2379 fwrite(t->data, t->len, 1, fi);
2381 ttf_table_delete(0, t);
2384 void ttf_dump(ttf_t*ttf)
2386 msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
2387 ttf_table_t*table = ttf->tables;
2389 U32 tag = table->id;
2390 msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)",
2391 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
2392 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
2393 table = table->next;
2395 //ttf_table_dump(ttf_find_table(ttf, TAG_MAXP));
2403 void ttf_destroy_tables(ttf_t*ttf)
2405 ttf_table_t*table = ttf->tables;
2407 ttf_table_t*next = table->next;
2414 void ttf_reduce(ttf_t*ttf)
2416 ttf_destroy_tables(ttf);
2418 void ttf_destroy(ttf_t*ttf)
2420 ttf_destroy_tables(ttf);
2433 int main(int argn, const char*argv[])
2435 setConsoleLogging(7);
2436 const char*filename = "comic.ttf";
2439 //msg("<notice> Loading %s", filename);
2440 memfile_t*m = memfile_open(filename);
2441 ttf_t*ttf = ttf_load(m->data, m->len);
2444 msg("<error> Couldn't load %s", filename);
2449 ttf_create_truetype_tables(ttf);
2454 //printf("os2 version: %04x (%d), maxp size: %d\n",
2455 // ttf->os2->version, ttf->os2->size, ttf->maxp->size);
2456 ttf_save_eot(ttf, "testfont.eot");
2457 ttf_save(ttf, "testfont.ttf");