2 Parser and writer for truetype font files.
4 Part of the swftools package.
6 Copyright (c) 2010 Matthias Kramm <kramm@quiss.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
32 #define TTCFTAG 0x74746366
34 #define OPENTYPE 0x4f54544f
35 #define TRUETYPE_MACOS 0x74727565
36 #define VERSION_1_0 0x00010000
38 #define TAG_OS2 0x4f532f32
39 #define TAG_CMAP 0x636d6170
40 #define TAG_GLYF 0x676c7966 //required for non opentype
41 #define TAG_HEAD 0x68656164 //required
42 #define TAG_HHEA 0x68686561 //required
43 #define TAG_HMTX 0x686d7478 //required
44 #define TAG_VHEA 0x86686561
45 #define TAG_VMTX 0x866d7478
46 #define TAG_KERN 0x6b65726e
47 #define TAG_LOCA 0x6c6f6361 //required for non opentype
48 #define TAG_MAXP 0x6d617870 //required
49 #define TAG_NAME 0x6e616d65
50 #define TAG_POST 0x706f7374
51 #define TAG_CFF 0x43464620 //required for opentype
52 #define TAG_CVT 0x63767420
53 #define TAG_FPGM 0x6670676d
54 #define TAG_GASP 0x67617370
55 #define TAG_PREP 0x70726570
58 static U32 checksum_block(U8*_data, int len)
64 int len_minus_4 = len-4;
65 for(pos=0;pos<=len_minus_4;pos+=4) {
66 sum += data[pos]<<24|data[pos+1]<<16|data[pos+2]<<8|data[pos+3];
69 if(left == 1) sum+= data[pos+0]<<24;
70 if(left == 2) sum+= data[pos+0]<<24|data[pos+1]<<16;
71 if(left == 3) sum+= data[pos+0]<<24|data[pos+1]<<16|data[pos+2]<<8;
75 typedef struct _memreader {
81 static U8 readU8(memreader_t*r)
83 return r->mem[r->pos++];
85 static inline U16 readU16(memreader_t*r)
87 if(r->pos+2>r->size) return 0;
88 U16 val = r->mem[r->pos]<<8|
93 static S16 readS16(memreader_t*r)
95 return (S16)readU16(r);
97 static U32 readU32(memreader_t*r)
99 if(r->pos+4>r->size) return 0;
100 U32 val = r->mem[r->pos]<<24|
101 r->mem[r->pos+1]<<16|
107 static void readBlock(memreader_t*r, void*dest, int len)
109 int remaining = r->size-r->pos;
110 if(len > remaining) {
111 memcpy(dest, r->mem+r->pos, remaining);
112 memset(dest+remaining, 0, len - remaining);
115 memcpy(dest, r->mem+r->pos, len);
119 static void reader_reset(memreader_t*r)
123 #define INIT_READ(r,data,length,pos) memreader_t r = {(data),(pos),(length)};
125 static void expand(ttf_table_t*w, int newsize)
127 int v1 = (newsize+63)&~63;
128 int v2 = w->len + w->len / 2;
129 w->memsize = v1>v2?v1:v2;
130 w->data = rfx_realloc(w->data, w->memsize);
132 static inline void writeU8(ttf_table_t*w, unsigned char b)
134 if(w->memsize<w->len+1)
136 w->data[w->len++] = b;
138 static inline void writeU16(ttf_table_t*w, unsigned short v)
140 if(w->memsize<w->len+2)
142 w->data[w->len++] = v>>8;
143 w->data[w->len++] = v;
145 static inline void writeU16_LE(ttf_table_t*w, unsigned short v)
147 if(w->memsize<w->len+2)
149 w->data[w->len++] = v;
150 w->data[w->len++] = v>>8;
152 #define writeS16 writeU16
153 static inline void writeU32(ttf_table_t*w, unsigned long v)
155 if(w->memsize<w->len+4)
157 w->data[w->len++] = v>>24;
158 w->data[w->len++] = v>>16;
159 w->data[w->len++] = v>>8;
160 w->data[w->len++] = v;
162 static inline void writeU32_LE(ttf_table_t*w, unsigned long v)
164 if(w->memsize<w->len+4)
166 w->data[w->len++] = v;
167 w->data[w->len++] = v>>8;
168 w->data[w->len++] = v>>16;
169 w->data[w->len++] = v>>24;
171 static inline void writeBlock(ttf_table_t*w, void*data, int len)
173 if(w->memsize<w->len+len)
174 expand(w, w->len+len);
175 memcpy(w->data+w->len, data, len);
179 ttf_table_t*ttf_table_new(U32 id)
181 ttf_table_t*t = rfx_calloc(sizeof(ttf_table_t));
186 ttf_table_t*ttf_addtable(ttf_t*ttf, U32 id)
188 ttf_table_t*t = ttf_table_new(id);
190 ttf_table_t*before,*after=0;
191 for(before=ttf->tables; before&&before->id<id; before=before->next) {
194 if(before && before->id == id) {
195 msg("<error> Error: duplicate table %08x", id);
203 t->next = ttf->tables;
207 t->next = after->next;
214 ttf_table_t*ttf_find_table(ttf_t*ttf, U32 id)
216 ttf_table_t*table = ttf->tables;
224 void ttf_table_delete(ttf_t*ttf, ttf_table_t*table)
226 if(ttf && ttf->tables == table) {
227 ttf->tables = table->next;
230 table->prev->next = table->next;
232 table->next->prev = table->prev;
236 U32 ttf_table_checksum(ttf_table_t*t)
238 U32 checksum = checksum_block(t->data, t->len);
239 if(t->id==TAG_HEAD && t->len>=12) {
240 /* the checksum for the HEAD table is calculated by masking out
241 the checksumadjust field */
242 U32 adjust = t->data[8]<<24|t->data[9]<<16|t->data[10]<<8|t->data[11];
247 static U8 printable(U8 a)
249 if(a<32 || a==127) return '.';
252 static void hexdump(U8*data, int len, const char*prefix)
256 printf("%s -=> ",prefix);
258 printf("%02x ", data[t]);
259 ascii[t&15] = printable(data[t]);
260 if((t && ((t&15)==15)) || (t==len-1))
264 for(s=p-1;s<16;s++) {
268 printf(" %s\n", ascii);
270 printf(" %s\n%s -=> ",ascii,prefix);
274 static void ttf_table_dump(ttf_table_t*t, const char*prefix)
277 hexdump(t->data, t->len, prefix);
280 static table_head_t*head_new(ttf_t*ttf)
282 table_head_t*head = rfx_calloc(sizeof(table_head_t));
283 head->units_per_em = 1024;
285 if(ttf->num_glyphs) {
286 head->xmin = ttf->glyphs[0].xmin;
287 head->ymin = ttf->glyphs[0].ymin;
288 head->xmax = ttf->glyphs[0].xmax;
289 head->ymax = ttf->glyphs[0].ymax;
290 for(t=1;t<ttf->num_glyphs;t++) {
291 if(ttf->glyphs[t].xmin < head->xmin) head->xmin = ttf->glyphs[t].xmin;
292 if(ttf->glyphs[t].ymin < head->ymin) head->ymin = ttf->glyphs[t].ymin;
293 if(ttf->glyphs[t].xmax > head->xmax) head->xmax = ttf->glyphs[t].xmax;
294 if(ttf->glyphs[t].ymax > head->ymax) head->ymax = ttf->glyphs[t].ymax;
298 head->lowest_readable_size = 8; // not sure what font renderers actually do with this
302 static int head_parse(ttf_t*ttf, memreader_t*r)
304 ttf->head = rfx_calloc(sizeof(table_head_t));
305 U32 version = readU32(r);
306 if(version!=VERSION_1_0)
307 msg("<warning> Font HEAD has unknown version %08x", version);
308 U32 revision = readU32(r);
309 U32 checksum2 = readU32(r);
310 U32 magic = readU32(r);
311 if(magic!=0x5f0f3cf5)
312 msg("<warning> Font HEAD has unknown magic number %08x", magic);
313 ttf->head->flags = readU16(r);
314 ttf->head->units_per_em = readU16(r);
315 readU32(r);readU32(r); //created
316 readU32(r);readU32(r); //modified
317 ttf->head->xmin = readU16(r);
318 ttf->head->ymin = readU16(r);
319 ttf->head->xmax = readU16(r);
320 ttf->head->ymax = readU16(r);
321 ttf->head->macStyle = readU16(r);
322 ttf->head->lowest_readable_size = readU16(r); //in pixels
323 ttf->head->dir_hint = readS16(r);
324 int loc_index = readS16(r); //used in 'loca' table
326 msg("<warning> loca index format %d unknown", loc_index);
327 U16 glyph_data_format = readS16(r);
328 if(glyph_data_format!=0)
329 msg("<warning> Font glyph data format unknown: %04x", glyph_data_format);
330 if(r->pos < r->size) {
331 msg("<warning> Leftover bytes (%d) in HEAD tag", r->size - r->pos);
335 static void head_write(ttf_t*ttf, ttf_table_t*w, int loca_size)
337 writeU32(w, 0x10000);
338 writeU32(w, 0x10000);
339 writeU32(w, 0); //checksum
340 writeU32(w, 0x5f0f3cf5); //magic
341 writeU16(w, ttf->head->flags);
342 writeU16(w, ttf->head->units_per_em);
343 writeU32(w, 0);writeU32(w, 0); //created
344 writeU32(w, 0);writeU32(w, 0); //modified
345 writeU16(w, ttf->head->xmin);
346 writeU16(w, ttf->head->ymin);
347 writeU16(w, ttf->head->xmax);
348 writeU16(w, ttf->head->ymax);
349 writeU16(w, ttf->head->macStyle);
350 writeU16(w, ttf->head->lowest_readable_size);
351 writeS16(w, ttf->head->dir_hint);
352 writeS16(w, loca_size); //loca index size (32 bit)
353 writeS16(w, 0); //glyph data format
355 static void head_dump(ttf_t*ttf)
357 printf("head->flags: %d\n", ttf->head->flags);
358 printf("head->units_per_em: %d\n", ttf->head->units_per_em);
359 printf("head->xmin: %d\n", ttf->head->xmin);
360 printf("head->ymin: %d\n", ttf->head->ymin);
361 printf("head->xmax: %d\n", ttf->head->xmax);
362 printf("head->ymax: %d\n", ttf->head->ymax);
363 printf("head->macStyle: %d\n", ttf->head->macStyle);
364 printf("head->lowest_readable_size: %d\n", ttf->head->lowest_readable_size);
365 printf("head->dir_hint: %d\n", ttf->head->dir_hint);
367 static void head_delete(ttf_t*ttf)
375 static table_os2_t*os2_new(ttf_t*ttf)
377 table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
378 if(ttf->num_glyphs) {
381 for(t=0;t<ttf->num_glyphs;t++) {
382 average_width += (ttf->glyphs[t].advance + ttf->glyphs[t].bearing);
384 os2->xAvgCharWidth = average_width / ttf->num_glyphs;
387 /* that's what everybody seems to fill in */
388 os2->usWeightClass = 400;
389 os2->usWidthClass = 5;
392 int advance = (ttf->head->xmax - ttf->head->xmin)/2;
393 int height = (ttf->head->xmax - ttf->head->xmin);
395 /* I do believe a sane font rendering engine will actually use
396 the font advance here- the subscript/superscript position will
397 not be the same for each glyph */
398 os2->ySuperscriptXSize = os2->ySubscriptXSize = (ttf->head->xmax - ttf->head->xmin)/2;
399 os2->ySuperscriptYSize = os2->ySubscriptYSize = (ttf->head->ymax - ttf->head->ymin)/2;
400 os2->ySubscriptXOffset = advance;
401 os2->ySubscriptYOffset = 0;
402 os2->ySuperscriptXOffset = advance;
403 os2->ySuperscriptYOffset = (ttf->head->ymax - ttf->head->ymin)/2;
404 os2->yStrikeoutSize = ttf->head->units_per_em / 10;
405 os2->yStrikeoutPosition = ymid;
406 os2->usWinAscent = ttf->ascent;
407 os2->usWinDescent = -ttf->descent;
408 os2->sxHeight = ymid;
409 os2->sCapHeight = height*2/3;
411 os2->panose_Weight = 4;
413 /* strictly speaking we'd have to set 92/64 bits in these tables, depending on
414 what parts of the unicode table is filled. (e.g. bit 90 = tibetan). */
415 os2->ulCharRange[0] = 1;
416 os2->ulCharRange[1] = 0;
417 os2->ulCharRange[2] = 0;
418 os2->ulCharRange[3] = 0;
419 os2->ulCodePageRange1 = 1;
420 os2->ulCodePageRange2 = 0;
422 if(ttf->unicode_size) {
424 for(min=0;min<ttf->unicode_size;min++)
425 if(ttf->unicode[min]) break;
426 for(max=ttf->unicode_size-1;max>=0;max--)
427 if(ttf->unicode[max]) break;
429 os2->fsFirstCharIndex = min;
430 os2->fsLastCharIndex = max;
433 os2->sTypoAscender = ttf->ascent;
434 os2->sTypoDescender = ttf->descent;
435 os2->sTypoLineGap = ttf->lineGap;
437 os2->usDefaultChar = 0;
438 os2->usBreakChar = (ttf->unicode_size>0x20 && ttf->unicode[0x20])?0x20:0;
439 os2->usMaxContext = 0; // we don't use ligatures yet
442 static table_os2_t*os2_parse(memreader_t*r)
444 table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
445 U16 version = readU16(r);
450 if(version!=0 && version!=1 && version!=2 && version!=3)
451 msg("<warning> Unknown OS2 version: %04x", version);
452 os2->xAvgCharWidth = readS16(r);
453 os2->usWeightClass = readU16(r);
454 os2->usWidthClass = readU16(r);
456 os2->ySubscriptXSize = readU16(r);
457 os2->ySubscriptYSize = readU16(r);
458 os2->ySubscriptXOffset = readU16(r);
459 os2->ySubscriptYOffset = readU16(r);
460 os2->ySuperscriptXSize = readU16(r);
461 os2->ySuperscriptYSize = readU16(r);
462 os2->ySuperscriptXOffset = readU16(r);
463 os2->ySuperscriptYOffset = readU16(r);
464 os2->yStrikeoutSize = readU16(r);
465 os2->yStrikeoutPosition = readU16(r);
466 os2->sFamilyClass = readU16(r);
467 os2->panose_FamilyType = readU8(r);
468 os2->panose_SerifStyle = readU8(r);
469 os2->panose_Weight = readU8(r);
470 os2->panose_Proportion = readU8(r);
471 os2->panose_Contrast = readU8(r);
472 os2->panose_StrokeVariation = readU8(r);
473 os2->panose_ArmStyle = readU8(r);
474 os2->panose_Letterform = readU8(r);
475 os2->panose_Midline = readU8(r);
476 os2->panose_XHeight = readU8(r);
477 os2->ulCharRange[0] = readU32(r);
478 os2->ulCharRange[1] = readU32(r);
479 os2->ulCharRange[2] = readU32(r);
480 os2->ulCharRange[3] = readU32(r);
482 os2->fsSelection = readU16(r);
483 os2->fsFirstCharIndex = readU16(r);
484 os2->fsLastCharIndex = readU16(r);
485 os2->sTypoAscender = readS16(r);
486 os2->sTypoDescender = readS16(r);
487 os2->sTypoLineGap = readS16(r);
488 os2->usWinAscent = readU16(r);
489 os2->usWinDescent = readU16(r);
490 if(version<1) return os2;
491 os2->ulCodePageRange1 = readU32(r);
492 os2->ulCodePageRange2 = readU32(r);
493 if(version<2) return os2;
494 os2->sxHeight = readS16(r);
495 os2->sCapHeight = readS16(r);
496 os2->usDefaultChar = readU16(r);
497 os2->usBreakChar = readU16(r);
498 os2->usMaxContext = readU16(r);
500 if(r->pos < r->size) {
501 msg("<warning> Leftover bytes (%d) in OS2 tag", r->size - r->pos);
505 static void os2_write(ttf_t*ttf, ttf_table_t*w)
507 table_os2_t*os2 = ttf->os2;
509 if(os2->sxHeight|os2->sCapHeight|os2->usDefaultChar|os2->usBreakChar|os2->usMaxContext) {
512 writeU16(w, version);
513 writeS16(w, os2->xAvgCharWidth);
514 writeU16(w, os2->usWeightClass);
515 writeU16(w, os2->usWidthClass);
516 writeU16(w, 0); //fstype
517 writeU16(w, os2->ySubscriptXSize);
518 writeU16(w, os2->ySubscriptYSize);
519 writeU16(w, os2->ySubscriptXOffset);
520 writeU16(w, os2->ySubscriptYOffset);
521 writeU16(w, os2->ySuperscriptXSize);
522 writeU16(w, os2->ySuperscriptYSize);
523 writeU16(w, os2->ySuperscriptXOffset);
524 writeU16(w, os2->ySuperscriptYOffset);
525 writeU16(w, os2->yStrikeoutSize);
526 writeU16(w, os2->yStrikeoutPosition);
527 writeU16(w, os2->sFamilyClass);
528 writeU8(w, os2->panose_FamilyType);
529 writeU8(w, os2->panose_SerifStyle);
530 writeU8(w, os2->panose_Weight);
531 writeU8(w, os2->panose_Proportion);
532 writeU8(w, os2->panose_Contrast);
533 writeU8(w, os2->panose_StrokeVariation);
534 writeU8(w, os2->panose_ArmStyle);
535 writeU8(w, os2->panose_Letterform);
536 writeU8(w, os2->panose_Midline);
537 writeU8(w, os2->panose_XHeight);
538 writeU32(w, os2->ulCharRange[0]);
539 writeU32(w, os2->ulCharRange[1]);
540 writeU32(w, os2->ulCharRange[2]);
541 writeU32(w, os2->ulCharRange[3]);
542 writeU32(w, 0x53434244); //vendor
543 writeU16(w, os2->fsSelection);
544 writeU16(w, os2->fsFirstCharIndex);
545 writeU16(w, os2->fsLastCharIndex);
546 writeS16(w, os2->sTypoAscender);
547 writeS16(w, os2->sTypoDescender);
548 writeS16(w, os2->sTypoLineGap);
549 writeU16(w, os2->usWinAscent);
550 writeU16(w, os2->usWinDescent);
551 if(version<1) return;
552 writeU32(w, os2->ulCodePageRange1);
553 writeU32(w, os2->ulCodePageRange2);
554 if(version<2) return;
555 writeS16(w, os2->sxHeight);
556 writeS16(w, os2->sCapHeight);
557 writeU16(w, os2->usDefaultChar);
558 writeU16(w, os2->usBreakChar);
559 writeU16(w, os2->usMaxContext);
561 static void os2_dump(ttf_t*ttf)
563 table_os2_t*os2 = ttf->os2;
565 printf("os2->xAvgCharWidth: %d\n", os2->xAvgCharWidth);
566 printf("os2->usWeightClass: %d\n", os2->usWeightClass);
567 printf("os2->usWidthClass: %d\n", os2->usWidthClass);
568 printf("os2->ySubscriptXSize: %d\n", os2->ySubscriptXSize);
569 printf("os2->ySubscriptYSize: %d\n", os2->ySubscriptYSize);
570 printf("os2->ySubscriptXOffset: %d\n", os2->ySubscriptXOffset);
571 printf("os2->ySubscriptYOffset: %d\n", os2->ySubscriptYOffset);
572 printf("os2->ySuperscriptXSize: %d\n", os2->ySuperscriptXSize);
573 printf("os2->ySuperscriptYSize: %d\n", os2->ySuperscriptYSize);
574 printf("os2->ySuperscriptXOffset: %d\n", os2->ySuperscriptXOffset);
575 printf("os2->ySuperscriptYOffset: %d\n", os2->ySuperscriptYOffset);
576 printf("os2->yStrikeoutSize: %d\n", os2->yStrikeoutSize);
577 printf("os2->yStrikeoutPosition: %d\n", os2->yStrikeoutPosition);
578 printf("os2->sFamilyClass: %d\n", os2->sFamilyClass);
579 printf("os2->panose_FamilyType: %d\n", os2->panose_FamilyType);
580 printf("os2->panose_SerifStyle: %d\n", os2->panose_SerifStyle);
581 printf("os2->panose_Weight: %d\n", os2->panose_Weight);
582 printf("os2->panose_Proportion: %d\n", os2->panose_Proportion);
583 printf("os2->panose_Contrast: %d\n", os2->panose_Contrast);
584 printf("os2->panose_StrokeVariation: %d\n", os2->panose_StrokeVariation);
585 printf("os2->panose_ArmStyle: %d\n", os2->panose_ArmStyle);
586 printf("os2->panose_Letterform: %d\n", os2->panose_Letterform);
587 printf("os2->panose_Midline: %d\n", os2->panose_Midline);
588 printf("os2->panose_XHeight: %d\n", os2->panose_XHeight);
589 printf("os2->ulCharRange[0]: %d\n", os2->ulCharRange[0]);
590 printf("os2->ulCharRange[1]: %d\n", os2->ulCharRange[1]);
591 printf("os2->ulCharRange[2]: %d\n", os2->ulCharRange[2]);
592 printf("os2->ulCharRange[3]: %d\n", os2->ulCharRange[3]);
593 printf("os2->fsSelection: %d\n", os2->fsSelection);
594 printf("os2->fsFirstCharIndex: %d\n", os2->fsFirstCharIndex);
595 printf("os2->fsLastCharIndex: %d\n", os2->fsLastCharIndex);
596 printf("os2->sTypoAscender: %d\n", os2->sTypoAscender);
597 printf("os2->sTypoDescender: %d\n", os2->sTypoDescender);
598 printf("os2->sTypoLineGap: %d\n", os2->sTypoLineGap);
599 printf("os2->usWinAscent: %d\n", os2->usWinAscent);
600 printf("os2->usWinDescent: %d\n", os2->usWinDescent);
601 printf("os2->ulCodePageRange1: %d\n", os2->ulCodePageRange1);
602 printf("os2->ulCodePageRange2: %d\n", os2->ulCodePageRange2);
603 printf("os2->sxHeight: %d\n", os2->sxHeight);
604 printf("os2->sCapHeight: %d\n", os2->sCapHeight);
605 printf("os2->usDefaultChar: %d\n", os2->usDefaultChar);
606 printf("os2->usBreakChar: %d\n", os2->usBreakChar);
607 printf("os2->usMaxContext: %d\n", os2->usMaxContext);
609 static void os2_delete(ttf_t*ttf)
616 static table_maxp_t*maxp_new(ttf_t*ttf)
618 table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
621 if(ttf->num_glyphs) {
623 for(t=0;t<ttf->num_glyphs;t++) {
624 if(ttf->glyphs[t].num_points>max)
625 max = ttf->glyphs[t].num_points;
628 for(s=0;s<ttf->glyphs[t].num_points;s++) {
629 if(ttf->glyphs[t].points[s].flags&GLYPH_CONTOUR_END)
632 if(maxp->maxContours < contours)
633 maxp->maxContours = contours;
635 maxp->maxPoints = max;
637 /* we don't generate composite glyphs yet */
638 maxp->maxComponentPoints = 0;
639 maxp->maxComponentContours = 0;
643 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
645 U32 version = readU32(r);
646 ttf->num_glyphs = readU16(r);
647 /* according to freetype, older fonts (version<0x10000)
648 apparently only contain the number of glyphs. this is
649 rather rare, though. */
650 if(version<0x10000 && r->size==6) return 0;
653 msg("<warning> Truncated maxp table (version %d)", version);
655 table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
656 maxp->maxPoints = readU16(r);
657 maxp->maxContours = readU16(r);
658 maxp->maxComponentPoints = readU16(r);
659 maxp->maxComponentContours = readU16(r);
660 maxp->maxZones = readU16(r);
661 maxp->maxTwilightPoints = readU16(r);
662 maxp->maxStorage = readU16(r);
663 maxp->maxFunctionDefs = readU16(r);
664 maxp->maxInstructionDefs = readU16(r);
665 maxp->maxStackElements = readU16(r);
666 maxp->maxSizeOfInstructions = readU16(r);
667 maxp->maxComponentElements = readU16(r);
668 maxp->maxComponentDepth = readU16(r);
671 static void maxp_write(ttf_t*ttf, ttf_table_t*w)
673 table_maxp_t*maxp = ttf->maxp;
675 /* version 0.5 simplified maxp table */
676 writeU32(w, 0x00005000);
677 writeU16(w, ttf->num_glyphs);
680 writeU32(w, 0x10000); //version
681 writeU16(w, ttf->num_glyphs);
682 writeU16(w, maxp->maxPoints);
683 writeU16(w, maxp->maxContours);
684 writeU16(w, maxp->maxComponentPoints);
685 writeU16(w, maxp->maxComponentContours);
686 writeU16(w, maxp->maxZones);
687 writeU16(w, maxp->maxTwilightPoints);
688 writeU16(w, maxp->maxStorage);
689 writeU16(w, maxp->maxFunctionDefs);
690 writeU16(w, maxp->maxInstructionDefs);
691 writeU16(w, maxp->maxStackElements);
692 writeU16(w, maxp->maxSizeOfInstructions);
693 writeU16(w, maxp->maxComponentElements);
694 writeU16(w, maxp->maxComponentDepth);
696 static void maxp_dump(ttf_t*ttf)
698 table_maxp_t*maxp = ttf->maxp;
700 printf("maxp->maxPoints: %d\n", maxp->maxPoints);
701 printf("maxp->maxContours: %d\n", maxp->maxContours);
702 printf("maxp->maxComponentPoints: %d\n", maxp->maxComponentPoints);
703 printf("maxp->maxComponentContours: %d\n", maxp->maxComponentContours);
704 printf("maxp->maxZones: %d\n", maxp->maxZones);
705 printf("maxp->maxTwilightPoints: %d\n", maxp->maxTwilightPoints);
706 printf("maxp->maxStorage: %d\n", maxp->maxStorage);
707 printf("maxp->maxFunctionDefs: %d\n", maxp->maxFunctionDefs);
708 printf("maxp->maxInstructionDefs: %d\n", maxp->maxInstructionDefs);
709 printf("maxp->maxStackElements: %d\n", maxp->maxStackElements);
710 printf("maxp->maxSizeOfInstructions: %d\n", maxp->maxSizeOfInstructions);
711 printf("maxp->maxComponentElements: %d\n", maxp->maxComponentElements);
712 printf("maxp->maxComponentDepth: %d\n", maxp->maxComponentDepth);
714 static void maxp_delete(ttf_t*ttf)
721 static table_hea_t*hea_new(ttf_t*ttf)
723 table_hea_t*hea = rfx_calloc(sizeof(table_hea_t));
724 if(ttf->num_glyphs) {
726 for(t=0;t<ttf->num_glyphs;t++) {
727 if(ttf->glyphs[t].advance > hea->advanceWidthMax)
728 hea->advanceWidthMax = ttf->glyphs[t].advance;
729 if(ttf->glyphs[t].xmin < hea->minLeftSideBearing)
730 hea->minLeftSideBearing = ttf->glyphs[t].xmin;
731 if(ttf->glyphs[t].xmax < hea->minRightSideBearing)
732 hea->minRightSideBearing = ttf->glyphs[t].xmax;
733 int width = ttf->glyphs[t].xmax - ttf->glyphs[t].xmin;
734 if(width > hea->xMaxExtent)
735 hea->xMaxExtent = width;
737 hea->caretSlopeRise = 1;
741 static int hea_parse(memreader_t*r, ttf_t*ttf)
743 table_hea_t*hea = ttf->hea = rfx_calloc(sizeof(table_hea_t));
744 U32 version = readU32(r);
745 ttf->ascent = readS16(r);
746 ttf->descent = readS16(r);
747 ttf->lineGap = readS16(r);
748 hea->advanceWidthMax = readU16(r);
749 hea->minLeftSideBearing = readS16(r);
750 hea->minRightSideBearing = readS16(r);
751 hea->xMaxExtent = readS16(r);
752 hea->caretSlopeRise = readS16(r);
753 hea->caretSlopeRun = readS16(r);
754 hea->caretOffset = readS16(r);
755 readS16(r); //reserved[0]
756 readS16(r); //reserved[1]
757 readS16(r); //reserved[2]
758 readS16(r); //reserved[3]
759 S16 metricDataFormat = readS16(r); //should be 0
760 if(metricDataFormat!=0) {
761 msg("<warning> Unknown metric format %d", metricDataFormat);
763 int num_advances = readU16(r);
764 if(num_advances > ttf->num_glyphs) {
765 msg("<warning> bad number of horizontal metrics: %d", num_advances);
766 num_advances = ttf->num_glyphs;
770 static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances)
772 table_hea_t*hea = ttf->hea;
773 writeU32(w, 0x00010000);
774 writeS16(w, ttf->ascent);
775 writeS16(w, ttf->descent);
776 writeS16(w, ttf->lineGap);
777 writeU16(w, hea->advanceWidthMax);
778 writeS16(w, hea->minLeftSideBearing);
779 writeS16(w, hea->minRightSideBearing);
780 writeS16(w, hea->xMaxExtent);
781 writeS16(w, hea->caretSlopeRise);
782 writeS16(w, hea->caretSlopeRun);
783 writeS16(w, hea->caretOffset);
784 writeS16(w, 0); //reserved
785 writeS16(w, 0); //reserved
786 writeS16(w, 0); //reserved
787 writeS16(w, 0); //reserved
788 writeS16(w, 0); //metricDataFormat
789 writeU16(w, num_advances);
792 static void hea_dump(ttf_t*ttf)
794 table_hea_t*hea = ttf->hea;
796 const char*dir = ttf->is_vertical?"v":"h";
797 printf("%shea->ascent: %d\n", dir, ttf->ascent);
798 printf("%shea->descent: %d\n", dir, ttf->descent);
799 printf("%shea->lineGap: %d\n", dir, ttf->lineGap);
800 printf("%shea->advanceWidthMax: %d\n", dir, hea->advanceWidthMax);
801 printf("%shea->minLeftSideBearing: %d\n", dir, hea->minLeftSideBearing);
802 printf("%shea->minRightSideBearing: %d\n", dir, hea->minRightSideBearing);
803 printf("%shea->xMaxExtent: %d\n", dir, hea->xMaxExtent);
804 printf("%shea->caretSlopeRise: %d\n", dir, hea->caretSlopeRise);
805 printf("%shea->caretSlopeRun: %d\n", dir, hea->caretSlopeRun);
806 printf("%shea->caretOffset: %d\n", dir, hea->caretOffset);
808 static void hea_delete(ttf_t*ttf)
816 static void mtx_parse(memreader_t*r, ttf_t*ttf, int num_advances)
820 if(num_advances > r->size/4)
821 num_advances = r->size/4;
822 for(t=0;t<num_advances;t++) {
823 old_advance = ttf->glyphs[t].advance = readU16(r);
824 ttf->glyphs[t].bearing = readS16(r);
826 int rest = (r->size - num_advances*4)/2;
827 if(ttf->num_glyphs < num_advances+rest) {
828 rest = ttf->num_glyphs-num_advances;
830 for(t=0;t<rest;t++) {
831 ttf->glyphs[t].advance = old_advance;
832 ttf->glyphs[t].bearing = readS16(r);
835 static int mtx_write(ttf_t*ttf, ttf_table_t*w)
837 int num_advances = ttf->num_glyphs;
838 if(ttf->num_glyphs>=2) {
840 for(t=ttf->num_glyphs-1;t>0;t--) {
841 if(ttf->glyphs[t-1].advance !=
842 ttf->glyphs[t].advance) break;
844 /* we need to store all individual advances as well
845 as one entry for the constant */
850 for(t=0;t<num_advances;t++) {
851 writeU16(w, ttf->glyphs[t].advance);
852 writeU16(w, ttf->glyphs[t].bearing);
854 for(;t<ttf->num_glyphs;t++) {
855 writeU16(w, ttf->glyphs[t].bearing);
860 static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size)
863 int num = ttf->num_glyphs+1;
864 U32*locations = rfx_calloc(num*sizeof(U32));
867 char warn_unsorted = 1;
869 if(num*4 > r->size) {
870 msg("<warning> Short 'loca' table (32 bit): %d/%d", r->size/4, num);
873 if(num*4 < r->size) {
874 msg("<warning> Extraneous data (%d bytes) in 'loca' table (32 bit)", r->size-num*4);
877 locations[t] = loc = readU32(r);
878 if(lastloc > loc && warn_unsorted) {
879 msg("<warning> Unsorted 'loca' table (32 bit)");
885 if(num*2 > r->size) {
886 msg("<warning> Short 'loca' table (16 bit)");
889 if(num*2 < r->size) {
890 msg("<warning> Extraneous data (%d bytes) in 'loca' table (16 bit)", r->size-num*2);
893 locations[t] = loc = readU16(r)*2;
894 if(lastloc > loc && warn_unsorted) {
895 msg("<warning> Unsorted 'loca' table");
903 static int loca_write(ttf_t*ttf, ttf_table_t*w, U32*locations)
907 for(t=0;t<=ttf->num_glyphs;t++) {
908 if(locations[t]>=0x20000 || (locations[t]&1)) {
915 for(t=0;t<=ttf->num_glyphs;t++) {
916 writeU32(w, locations[t]);
920 for(t=0;t<=ttf->num_glyphs;t++) {
921 writeU16(w, locations[t]/2);
927 static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int glyphnr)
929 ttfglyph_t*glyph = &ttf->glyphs[glyphnr];
933 endpoints = malloc(sizeof(U16)*num_contours);
936 for(s=0;s<num_contours;s++) {
937 int pos = endpoints[s] = readU16(r);
939 msg("<warning> Unsorted endpoints array (len:%d) last=%d now=%d", s, pos, lastpos);
944 U16 code_len = readU16(r);
946 glyph->code = malloc(sizeof(U16)*code_len);
947 readBlock(r, glyph->code, code_len);
948 glyph->code_size = code_len;
954 /*msg("<notice> TTF Glyph %d) code_size=%d num_contours=%d glyph->num_points=%d %d/%d/%d/%d",
955 glyphnr, code_len, num_contours, glyph->num_points,
956 xmin, ymin, xmax, ymax);*/
957 INIT_READ(fx, r->mem, r->size, r->pos);
958 INIT_READ(fy, r->mem, r->size, r->pos);
960 glyph->num_points = endpoints[num_contours-1] + 1;
961 glyph->points = rfx_calloc(sizeof(ttfpoint_t)*glyph->num_points);
963 /* parse flag array (1st pass- to determine start of coordinates) */
965 while(num<glyph->num_points) {
968 msg("<error> Bad flags in glyph outline: %02x (at pos %d)", flag, num);
971 glyph->num_points = 0;
977 if(count+num>glyph->num_points) {
978 msg("<warning> Bad count (%d) in glyph (%d) (at pos %d)", count, glyphnr, num);
979 count = glyph->num_points-num;
984 /* parse flag array (2nd pass) and x coordinates */
989 int bytepos = r->pos;
990 while(num<glyph->num_points) {
991 U8 flag = readU8(&fx);
992 int count = flag&8?readU8(&fx)+1:1;
993 count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
996 if(contour_pos<num_contours && num==endpoints[contour_pos]) {
1001 if((flag&0x12) == 0x12) x += readU8(r);
1002 else if((flag&0x12) == 0x02) x -= readU8(r);
1003 else if((flag&0x12) == 0x00) x += readS16(r);
1005 glyph->points[num].x = x;
1006 U8 f = flag&GLYPH_ON_CURVE;
1007 if(is_start) f|=GLYPH_CONTOUR_START;
1008 if(is_end) f|=GLYPH_CONTOUR_END;
1009 glyph->points[num].flags = f;
1015 /* parse flag array (3rd pass) and y coordinates */
1018 while(num<glyph->num_points) {
1019 U8 flag = readU8(&fy);
1020 int count = flag&8?readU8(&fy)+1:1;
1021 count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
1023 if((flag&0x24) == 0x24) y += readU8(r);
1024 else if((flag&0x24) == 0x04) y -= readU8(r);
1025 else if((flag&0x24) == 0x00) y += readS16(r);
1026 glyph->points[num].y = y;
1033 static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
1036 char warn_about_compound_glyphs=0;
1037 for(t=0;t<ttf->num_glyphs;t++) {
1038 INIT_READ(r, rr->mem, rr->size, loca[t]);
1039 if(loca[t]==loca[t+1] || loca[t]==r.size)
1040 continue; //empty glyph
1041 if(r.pos+10>r.size) {
1042 msg("<warning> Truncated glyph entry %d/%d (or bad loca entry %d/%d, next loca: %d)",
1043 t, ttf->num_glyphs, loca[t], r.size, loca[t+1]);
1046 S16 num_contours = readS16(&r);
1047 ttf->glyphs[t].xmin = readS16(&r);
1048 ttf->glyphs[t].ymin = readS16(&r);
1049 ttf->glyphs[t].xmax = readS16(&r);
1050 ttf->glyphs[t].ymax = readS16(&r);
1052 if(num_contours<0) {
1053 if(warn_about_compound_glyphs)
1054 msg("<error> Compound glyphs not supported yet");
1055 warn_about_compound_glyphs=0;
1057 if(!parse_simple_glyph(ttf, &r, num_contours, t))
1063 void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
1065 /* endpoints array */
1067 for(s=0;s<g->num_points;s++) {
1068 if(g->points[s].flags&GLYPH_CONTOUR_END)
1073 writeU16(w, g->code_size);
1075 writeBlock(w, g->code, g->code_size);
1082 for(s=0;s<g->num_points;s++) {
1083 ttfpoint_t*p = &g->points[s];
1084 int dx = p->x - lastx;
1085 int dy = p->y - lasty;
1086 U8 flags = p->flags&GLYPH_ON_CURVE;
1089 } else if(dx<0 && dx>=-255) {
1091 } else if(dx>0 && dx<=255) {
1096 } else if(dy<0 && dy>=-255) {
1098 } else if(dy>0 && dy<=255) {
1101 if(flags == lastflag && flagcount<255) {
1106 writeU8(w, lastflag|8);
1107 writeU8(w, flagcount);
1109 writeU8(w, lastflag);
1120 writeU8(w, lastflag|8);
1121 writeU8(w, flagcount);
1123 writeU8(w, lastflag);
1128 int bytepos = w->len;
1129 for(s=0;s<g->num_points;s++) {
1130 ttfpoint_t*p = &g->points[s];
1131 int dx = p->x - lastx;
1132 if(dx>32767 || dx<-32768) {
1133 msg("<error> Coordinate overflow in glyph");
1136 if(dx>0 && dx<=255) writeU8(w, dx);
1137 else if(dx<0 && dx>=-255) writeU8(w, -dx);
1138 else if(dx) writeS16(w, dx);
1142 for(s=0;s<g->num_points;s++) {
1143 ttfpoint_t*p = &g->points[s];
1144 int dy = p->y - lasty;
1145 if(dy>32767 || dy<-32768) {
1146 msg("<error> Coordinate overflow in glyph");
1149 if(dy>0 && dy<=255) writeU8(w, dy);
1150 else if(dy<0 && dy>=-255) writeU8(w, -dy);
1151 else if(dy) writeS16(w, dy);
1154 U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
1156 U32*locations = malloc(sizeof(U32)*(ttf->num_glyphs+1));
1158 for(t=0;t<ttf->num_glyphs;t++) {
1159 locations[t] = w->len;
1160 ttfglyph_t*g = &ttf->glyphs[t];
1162 int num_contours = 0;
1163 for(s=0;s<g->num_points;s++) {
1164 if(g->points[s].flags&GLYPH_CONTOUR_END)
1167 writeS16(w, num_contours?num_contours:1);
1168 writeS16(w, g->xmin);
1169 writeS16(w, g->ymin);
1170 writeS16(w, g->xmax);
1171 writeS16(w, g->ymax);
1174 /* some ttf parsers can't deal with zero contours, so in the case
1175 of an empty glyph, write a single point (0,0) */
1176 writeU16(w, 0); //endpoint of 1st contour
1177 writeU16(w, g->code_size);
1179 writeBlock(w, g->code, g->code_size);
1180 writeU8(w, 0x31); //flag (xy=(0,0),on curve)
1182 write_simple_glyph(w, g);
1185 locations[t] = w->len;
1188 void glyf_dump(ttf_t* ttf)
1190 if(!ttf->glyphs) return;
1192 for(t=0;t<ttf->num_glyphs;t++) {
1193 ttfglyph_t*g = &ttf->glyphs[t];
1194 printf("glyph %d)\n", t);
1195 printf(" advance=%d\n", g->advance);
1196 printf(" bearing=%d\n", g->bearing);
1197 printf(" bbox=(%d/%d/%d/%d)\n", g->xmin, g->ymin, g->xmax, g->ymax);
1198 printf(" points=(");
1200 for(s=0;s<g->num_points;s++) {
1202 printf("%d/%d/0x%02x", g->points[s].x, g->points[s].y, g->points[s].flags);
1206 hexdump(g->code, g->code_size, " ");
1209 void glyf_delete(ttf_t* ttf)
1214 for(t=0;t<ttf->num_glyphs;t++) {
1215 if(ttf->glyphs[t].code) {
1216 free(ttf->glyphs[t].code);
1217 ttf->glyphs[t].code = 0;
1219 if(ttf->glyphs[t].points) {
1220 free(ttf->glyphs[t].points);
1221 ttf->glyphs[t].points = 0;
1224 free(ttf->glyphs);ttf->glyphs=0;
1227 static void grow_unicode(ttf_t*ttf, int index)
1231 ttf->unicode = rfx_calloc(sizeof(ttf->unicode[0])*size);
1232 } else if(ttf->unicode_size<size) {
1233 ttf->unicode = rfx_realloc(ttf->unicode, sizeof(ttf->unicode[0])*size);
1234 memset(ttf->unicode+ttf->unicode_size, 0, sizeof(ttf->unicode[0])*(size - ttf->unicode_size));
1236 ttf->unicode_size = size;
1238 void cmap_parse(memreader_t*r, ttf_t*ttf)
1240 readU16(r); // version (0)
1241 int num_subtables = readU16(r);
1244 if(r->pos+num_subtables*8 > r->size) {
1245 msg("<warning> CMap overflow");
1246 num_subtables = (r->size-r->pos)/8;
1249 for(t=0;t<num_subtables;t++) {
1250 U16 platform = readU16(r);
1251 U16 encoding = readU16(r);
1252 U32 offset = readU32(r);
1253 if(offset>r->size) {
1254 msg("<warning> CMAP table %d %d is out of bounds (%d)", platform, encoding, offset);
1258 int is_unicode = platform==0 ||
1259 platform==3 && encoding == 1 ||
1260 platform==3 && encoding == 10;
1265 INIT_READ(t, r->mem, r->size, offset);
1266 U16 format = readU16(&t);
1267 int length = readU16(&t);
1268 U16 language = readU16(&t);
1271 msg("<warning> Language code %02x in unicode mapping", language);
1276 if(t.pos+length > t.size) {
1277 msg("<warning> overflow in format 0 cmap table");
1280 data = malloc(num*sizeof(unicode_t));
1282 grow_unicode(ttf, num);
1283 for(s=0;s<num;s++) {
1284 ttf->unicode[s] = readU8(&t);
1286 } else if(format == 4) {
1287 U16 segment_count = readU16(&t);
1288 if(segment_count&1) {
1289 msg("<error> Bad segmentx2 count %d", segment_count);
1293 readU16(&t); //searchrange
1294 readU16(&t); //entry selector
1295 readU16(&t); //range shift
1296 INIT_READ(r_end, t.mem, t.size, t.pos);
1297 INIT_READ(r_start, t.mem, t.size, t.pos+2+segment_count*2);
1298 INIT_READ(r_delta, t.mem, t.size, t.pos+2+segment_count*4);
1299 INIT_READ(r_range, t.mem, t.size, t.pos+2+segment_count*6);
1300 int glyphmap_start = t.pos+2+segment_count*8;
1301 int glyphmap_size = t.size - glyphmap_start;
1303 for(s=0;s<segment_count;s++) {
1304 U16 start = readU16(&r_start);
1305 U16 end = readU16(&r_end);
1306 U16 delta = readU16(&r_delta);
1307 U16 range = readU16(&r_range);
1308 if(start==0xffff && end==0xffff && delta==1) {
1309 /* this is a common (maybe even required) occurence in fonts
1310 which explicitly map "unicode undefined" (0xffff) to
1311 "glyph undefined" (0).
1312 We don't want to blow our unicode table up to 65536 just
1313 because of this, so ignore this entry.
1317 grow_unicode(ttf, end);
1320 for(u=start;u<=end;u++) {
1321 ttf->unicode[u] = (u + delta) & 0xffff;
1324 int pos = r_range.pos-2+range;
1325 if(warn && pos+end-start+1 > t.size) {
1326 msg("<warning> glyphmap index out of bounds (%d-%d/%d)", pos, pos+end-start, t.size);
1329 INIT_READ(g, t.mem, t.size, pos);
1330 for(u=start;u<=end;u++) {
1331 ttf->unicode[u] = readU16(&g);
1338 static int segment_size(unicode_t*unicode, int pos, int size)
1342 for(s=pos;s<size;s++) {
1346 /* a segment costs us 8 bytes, so for more than 4 consecutive
1347 zero entries (16 bit each) in the glyph index array,
1348 it pays off to start a new segment */
1352 s -= count; // go to the last filled in entry
1357 void cmap_write(ttf_t* ttf, ttf_table_t*w)
1359 writeU16(w, 0); //version
1360 writeU16(w, 2); //two tables
1362 writeU16(w, 0); //platform (unicode)
1363 writeU16(w, 3); //encoding (unicode 2.0)
1364 writeU32(w, 20); //offset
1366 writeU16(w, 3); //platform (windows)
1367 writeU16(w, 1); //encoding (unicode basic multilingual plane UCS-2)
1368 writeU32(w, 20); //offset
1370 writeU16(w, 4); // format=4
1371 int length_pos = w->len;
1372 writeU16(w, 0); // length: we don't know yet
1373 writeU16(w, 0); // language (n/a for unicode)
1374 int num_segments_pos = w->len;
1375 writeU16(w, 0); //number of segments: we don't know yet either
1376 writeU16(w, 0); //searchrange
1377 writeU16(w, 0); //entry selector
1378 writeU16(w, 0); //range shift
1382 while(pos < ttf->unicode_size) {
1383 if(!ttf->unicode[pos]) {
1387 int s = segment_size(ttf->unicode, pos, ttf->unicode_size);
1392 num_segments++; // account for 0xffff mapping
1394 int glyphmap_start = w->len+2+num_segments*8;
1397 int end_pos = w->len;
1398 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
1399 writeU16(w, 0); //reserved byte
1400 int start_pos = w->len;
1401 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //start array
1402 int delta_pos = w->len;
1403 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //delta array
1404 int range_pos = w->len;
1405 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //range array
1407 /* backpatch number of segments */
1408 w->data[num_segments_pos++]=(num_segments*2)>>8;
1409 w->data[num_segments_pos++]=(num_segments*2);
1410 /* backpatch search range */
1411 int tmp = num_segments;
1412 int search_range = 0;
1417 w->data[num_segments_pos++]=(search_range*2)>>8;
1418 w->data[num_segments_pos++]=(search_range*2);
1419 /* backpatch entry selector */
1420 int entry_selector = 0;
1421 while(tmp>1) {tmp>>=1;entry_selector++;}
1422 w->data[num_segments_pos++]=entry_selector>>8;
1423 w->data[num_segments_pos++]=entry_selector;
1424 /* backpatch range shift */
1425 int range_shift = num_segments*2 - search_range;
1426 w->data[num_segments_pos++]=range_shift>>8;
1427 w->data[num_segments_pos++]=range_shift;
1431 while(pos < ttf->unicode_size) {
1432 if(!ttf->unicode[pos]) {
1436 U16 end = segment_size(ttf->unicode, pos, ttf->unicode_size);
1437 w->data[end_pos++]=end>>8;
1438 w->data[end_pos++]=end;
1439 w->data[start_pos++]=pos>>8;
1440 w->data[start_pos++]=pos;
1442 U16 delta = ttf->unicode[pos]-pos;
1444 for(s=pos+1;s<=end;s++) {
1445 U16 delta2 = ttf->unicode[s]-s;
1456 range = w->len - range_pos;
1457 for(s=pos;s<=end;s++) {
1458 writeU16(w, ttf->unicode[s]);
1461 w->data[delta_pos++]=delta>>8;
1462 w->data[delta_pos++]=delta;
1463 w->data[range_pos++]=range>>8;
1464 w->data[range_pos++]=range;
1469 /* write out a mapping from 0xffff to 0- seems to be required
1470 by some libraries (e.g. fonttools) */
1471 w->data[end_pos++]=0xff;
1472 w->data[end_pos++]=0xff;
1473 w->data[start_pos++]=0xff;
1474 w->data[start_pos++]=0xff;
1475 w->data[delta_pos++]=0;
1476 w->data[delta_pos++]=1;
1477 w->data[range_pos++]=0;
1478 w->data[range_pos++]=0;
1480 w->data[length_pos]=(w->len-20)>>8;
1481 w->data[length_pos+1]=w->len-20;
1483 void cmap_delete(ttf_t*ttf)
1489 ttf->unicode_size=0;
1491 static char*readString(memreader_t*r, int len)
1493 char*s = malloc(len+1);
1494 readBlock(r, s, len);
1498 void name_parse(memreader_t*r, ttf_t*ttf)
1500 U16 format = readU16(r);
1501 U16 count = readU16(r);
1502 U16 offset = readU16(r);
1505 for(t=0;t<count;t++) {
1506 U16 platform = readU16(r);
1507 U16 encoding = readU16(r);
1508 U16 language = readU16(r);
1509 U16 name_id = readU16(r);
1510 U16 len = readU16(r);
1511 U16 offset_2 = readU16(r);
1513 char ** read_name = 0;
1515 INIT_READ(ss, r->mem, r->size, offset+offset_2);
1516 if(!(platform==0 || (platform==1 && encoding==0)))
1519 INIT_READ(s, r->mem, r->size, offset+offset_2);
1522 case 1: read_name = &ttf->family_name; break;
1523 case 2: read_name = &ttf->subfamily_name; break;
1524 case 3: read_name = &ttf->font_uid; break;
1525 case 4: read_name = &ttf->full_name; break;
1526 case 5: read_name = &ttf->version_string; break;
1527 case 6: read_name = &ttf->postscript_name; break;
1528 default: read_name = 0;
1532 if (*read_name) free(*read_name);
1533 *read_name = readString(&s, len);
1537 void name_write(ttf_t*ttf, ttf_table_t*table)
1539 char*strings[6] = {ttf->family_name, ttf->subfamily_name, ttf->font_uid, ttf->full_name, ttf->version_string, ttf->postscript_name};
1540 int codes[6] = {1,2,3,4,5,6};
1542 writeU16(table, 0); //format
1545 int nr = sizeof(strings)/sizeof(strings[0]);
1551 writeU16(table, count); //count
1553 int offset_pos = table->len;
1554 writeU16(table, 0); //offset (will be filled in later)
1556 /* Windows expects the name table to be sorted by platform/encoding/language/name_id */
1560 writeU16(table, 1); //platform id (mac)
1561 writeU16(table, 0); //encoding id (latin-1)
1562 writeU16(table, 0); //language (english)
1563 writeU16(table, codes[t]);
1564 int len = strlen(strings[t]);
1565 writeU16(table, len);
1566 writeU16(table, offset);
1572 writeU16(table, 3); //platform id (windows)
1573 writeU16(table, 1); //encoding id (ucs-2)
1574 writeU16(table, 0x409); //language (US)
1575 writeU16(table, codes[t]);
1576 int len2 = strlen(strings[t]) * 2;
1577 writeU16(table, len2);
1578 writeU16(table, offset);
1583 table->data[offset_pos] = table->len>>8;
1584 table->data[offset_pos+1] = table->len;
1588 int len = strlen(strings[t]);
1589 writeBlock(table, strings[t], len);
1595 int len = strlen(strings[t]);
1596 for(s=0;s<len;s++) {
1598 writeU8(table, strings[t][s]);
1603 void name_delete(ttf_t*ttf)
1605 if(ttf->full_name) {
1606 free(ttf->full_name);
1609 if(ttf->family_name) {
1610 free(ttf->family_name);
1613 if(ttf->subfamily_name) {
1614 free(ttf->subfamily_name);
1615 ttf->subfamily_name=0;
1617 if(ttf->version_string) {
1618 free(ttf->version_string);
1619 ttf->version_string=0;
1622 free(ttf->font_uid);
1625 if(ttf->postscript_name) {
1626 free(ttf->postscript_name);
1627 ttf->postscript_name=0;
1631 static table_post_t*post_new(ttf_t*ttf)
1633 table_post_t*post = rfx_calloc(sizeof(table_post_t));
1636 void post_parse(memreader_t*r, ttf_t*ttf)
1638 table_post_t*post = ttf->post = rfx_calloc(sizeof(table_post_t));
1639 U16 format = readU16(r);
1640 post->italic_angle = readU16(r);
1641 post->underline_position = readU16(r);
1642 post->underline_thickness = readU16(r);
1643 U16 is_monospaced = readU16(r);
1644 readU16(r); // min mem 42
1646 readU16(r); // min mem 1
1649 void post_write(ttf_t*ttf, ttf_table_t*table)
1651 table_post_t*post = ttf->post;
1652 writeU32(table, 0x00030000);
1653 writeU32(table, post->italic_angle);
1654 writeU16(table, post->underline_position);
1655 writeU16(table, post->underline_thickness);
1656 writeU32(table, 0); //is monospaced TODO
1657 writeU32(table, 0); //min mem 42
1659 writeU32(table, 0); //min mem 1
1662 void post_delete(ttf_t*ttf)
1670 void cvt_parse(memreader_t*r, ttf_t*ttf)
1672 table_cvt_t*cvt = ttf->cvt = rfx_calloc(sizeof(table_cvt_t));
1673 cvt->num = r->size/2;
1674 cvt->values = malloc(cvt->num*sizeof(S16));
1676 for(t=0;t<cvt->num;t++) {
1677 cvt->values[t] = readS16(r);
1680 void cvt_write(ttf_t*ttf, ttf_table_t*table)
1682 table_cvt_t*cvt = ttf->cvt;
1684 for(t=0;t<cvt->num;t++) {
1685 writeS16(table, cvt->values[t]);
1688 void cvt_delete(ttf_t*ttf)
1691 if(ttf->cvt->values)
1692 free(ttf->cvt->values);
1698 static table_gasp_t*gasp_new(ttf_t*ttf)
1700 table_gasp_t*gasp = rfx_calloc(sizeof(table_gasp_t));
1702 gasp->records = rfx_calloc(sizeof(gasp->records[0])*gasp->num);
1704 gasp->records[0].size = 65535;
1705 gasp->records[0].behaviour = 15; //gridfit+grayscale rendering
1708 void gasp_parse(memreader_t*r, ttf_t*ttf)
1710 table_gasp_t*gasp = ttf->gasp = rfx_calloc(sizeof(table_gasp_t));
1711 readU16(r); //version
1712 int num = readU16(r);
1715 gasp->records = malloc(sizeof(gasp->records[0])*num);
1716 for(t=0;t<num;t++) {
1717 gasp->records[t].size = readU16(r);
1718 gasp->records[t].behaviour = readU16(r);
1721 void gasp_write(ttf_t*ttf, ttf_table_t*table)
1723 table_gasp_t*gasp = ttf->gasp;
1725 writeU16(table, gasp->num);
1727 for(t=0;t<gasp->num;t++) {
1728 writeU16(table, gasp->records[t].size);
1729 writeU16(table, gasp->records[t].behaviour);
1732 void gasp_delete(ttf_t*ttf)
1735 if(ttf->gasp->records)
1736 free(ttf->gasp->records);
1742 table_code_t*prep_new(ttf_t*ttf)
1744 table_code_t*prep = ttf->prep = rfx_calloc(sizeof(table_code_t));
1745 ttf_table_t*t = ttf_table_new(0);
1746 writeU8(t,0xb8);writeU16(t,0x1ff); // pushword(0x1ff)
1747 writeU8(t,0x85); //scanctrl (always do dropout, for all sizes)
1748 writeU8(t,0xb0);writeU8(t,1); // pushbyte(1)
1749 writeU8(t,0x8d); //scantype (simple dropout control w/o stubs)
1750 writeU8(t,0xb0);writeU8(t,5); // pushbyte(5)
1751 writeU8(t,0x8d); //scantype (for windows) smart dropout control w/o stubs
1752 prep->code = t->data;
1753 prep->size = t->len;
1758 void fpgm_parse(memreader_t*r, ttf_t*ttf)
1760 table_code_t*fpgm = ttf->fpgm = rfx_calloc(sizeof(table_code_t));
1761 if(!r->size) return;
1762 fpgm->size = r->size;
1763 fpgm->code = malloc(r->size);
1764 readBlock(r, fpgm->code, r->size);
1766 void fpgm_write(ttf_t*ttf, ttf_table_t*table)
1768 table_code_t*code = ttf->fpgm;
1769 writeBlock(table, code->code, code->size);
1771 void fpgm_delete(ttf_t*ttf)
1775 free(ttf->fpgm->code);
1781 void prep_parse(memreader_t*r, ttf_t*ttf)
1783 table_code_t*prep = ttf->prep = rfx_calloc(sizeof(table_code_t));
1784 if(!r->size) return;
1785 prep->size = r->size;
1786 prep->code = malloc(r->size);
1787 readBlock(r, prep->code, r->size);
1789 void prep_write(ttf_t*ttf, ttf_table_t*table)
1791 table_code_t*code = ttf->prep;
1792 writeBlock(table, code->code, code->size);
1794 void prep_delete(ttf_t*ttf)
1798 free(ttf->prep->code);
1804 static int ttf_parse_tables(ttf_t*ttf)
1808 table = ttf_find_table(ttf, TAG_HEAD);
1810 msg("<error> Font has no head table");
1813 INIT_READ(m, table->data, table->len, 0);
1814 int loc_index = head_parse(ttf, &m);
1815 ttf_table_delete(ttf, table);
1817 table = ttf_find_table(ttf, TAG_MAXP);
1819 msg("<error> Font has no maxp table");
1822 INIT_READ(m2, table->data, table->len, 0);
1823 ttf->maxp = maxp_parse(ttf, &m2);
1824 ttf_table_delete(ttf, table);
1826 if(!ttf->num_glyphs) {
1827 msg("<error> Invalid number of characters");
1830 ttf->glyphs = rfx_calloc(sizeof(ttfglyph_t)*ttf->num_glyphs);
1832 table = ttf_find_table(ttf, TAG_OS2);
1834 INIT_READ(m, table->data, table->len, 0);
1835 ttf->os2 = os2_parse(&m);
1836 ttf_table_delete(ttf, table);
1840 table = ttf_find_table(ttf, TAG_HHEA);
1842 INIT_READ(m, table->data, table->len, 0);
1843 int num_advances = hea_parse(&m, ttf);
1844 ttf_table_delete(ttf, table);
1846 table = ttf_find_table(ttf, TAG_HMTX);
1848 INIT_READ(m, table->data, table->len, 0);
1849 mtx_parse(&m, ttf, num_advances);
1850 ttf_table_delete(ttf, table);
1853 table = ttf_find_table(ttf, TAG_VHEA);
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_VMTX);
1862 INIT_READ(m, table->data, table->len, 0);
1863 mtx_parse(&m, ttf, num_advances);
1864 ttf_table_delete(ttf, table);
1867 msg("<error> Font contains neither HHEA nor VHEA");
1870 table = ttf_find_table(ttf, TAG_LOCA);
1872 INIT_READ(m, table->data, table->len, 0);
1873 U32*loca = loca_parse(&m, ttf, loc_index);
1874 ttf_table_delete(ttf, table);
1875 table = ttf_find_table(ttf, TAG_GLYF);
1877 INIT_READ(m, table->data, table->len, 0);
1878 glyf_parse(&m, ttf, loca);
1879 ttf_table_delete(ttf, table);
1884 table = ttf_find_table(ttf, TAG_CMAP);
1886 INIT_READ(m, table->data, table->len, 0);
1887 cmap_parse(&m, ttf);
1888 ttf_table_delete(ttf, table);
1891 table = ttf_find_table(ttf, TAG_POST);
1893 INIT_READ(m, table->data, table->len, 0);
1894 post_parse(&m, ttf);
1895 ttf_table_delete(ttf, table);
1898 table = ttf_find_table(ttf, TAG_NAME);
1900 INIT_READ(m, table->data, table->len, 0);
1901 name_parse(&m, ttf);
1902 ttf_table_delete(ttf, table);
1905 table = ttf_find_table(ttf, TAG_CVT);
1907 INIT_READ(m, table->data, table->len, 0);
1909 ttf_table_delete(ttf, table);
1912 table = ttf_find_table(ttf, TAG_GASP);
1914 INIT_READ(m, table->data, table->len, 0);
1915 gasp_parse(&m, ttf);
1916 ttf_table_delete(ttf, table);
1919 table = ttf_find_table(ttf, TAG_PREP);
1921 INIT_READ(m, table->data, table->len, 0);
1922 prep_parse(&m, ttf);
1923 ttf_table_delete(ttf, table);
1926 table = ttf_find_table(ttf, TAG_FPGM);
1928 INIT_READ(m, table->data, table->len, 0);
1929 fpgm_parse(&m, ttf);
1930 ttf_table_delete(ttf, table);
1935 static void ttf_collapse_tables(ttf_t*ttf)
1939 ttf_table_t*head = ttf_find_table(ttf, TAG_HEAD);
1941 return; //already collapsed
1944 table = ttf_addtable(ttf, TAG_MAXP);
1945 maxp_write(ttf, table);
1950 table = ttf_addtable(ttf, TAG_OS2);
1951 os2_write(ttf, table);
1956 if(!ttf->is_vertical) {
1957 table = ttf_addtable(ttf, TAG_HMTX);
1958 int num_advances = mtx_write(ttf, table);
1959 table = ttf_addtable(ttf, TAG_HHEA);
1960 hea_write(ttf, table, num_advances);
1963 table = ttf_addtable(ttf, TAG_VMTX);
1964 int num_advances = mtx_write(ttf, table);
1965 table = ttf_addtable(ttf, TAG_VHEA);
1966 hea_write(ttf, table, num_advances);
1972 if(ttf->num_glyphs) {
1974 table = ttf_addtable(ttf, TAG_CMAP);
1975 cmap_write(ttf, table);
1980 table = ttf_addtable(ttf, TAG_GLYF);
1981 U32*locations = glyf_write(ttf, table);
1982 table = ttf_addtable(ttf, TAG_LOCA);
1983 loca_size = loca_write(ttf, table, locations);
1989 if(ttf->full_name || ttf->family_name || ttf->subfamily_name || ttf->font_uid || ttf->postscript_name) {
1990 table = ttf_addtable(ttf, TAG_NAME);
1991 name_write(ttf, table);
1995 table = ttf_addtable(ttf, TAG_POST);
1996 post_write(ttf, table);
2000 table = ttf_addtable(ttf, TAG_CVT);
2001 cvt_write(ttf, table);
2005 table = ttf_addtable(ttf, TAG_GASP);
2006 gasp_write(ttf, table);
2010 table = ttf_addtable(ttf, TAG_FPGM);
2011 fpgm_write(ttf, table);
2015 table = ttf_addtable(ttf, TAG_PREP);
2016 prep_write(ttf, table);
2020 table = ttf_addtable(ttf, TAG_HEAD);
2021 head_write(ttf, table, loca_size);
2027 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
2028 ttf->version = VERSION_1_0;
2031 ttf_t* ttf_load(void*data, int length)
2033 INIT_READ(r,data,length, 0);
2036 msg("<error> Truncated Truetype file (%d bytes)", length);
2040 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
2041 ttf->version = readU32(&r);
2042 if(ttf->version == SWAP32(length)) {
2043 U32 fontDataSize = readU32(&r);
2044 U32 version = readU32(&r);
2045 U32 flags = readU32(&r);
2047 readBlock(&r, panose, 10);
2048 readU8(&r); //charset
2049 readU8(&r); //italoc
2050 readU32(&r); //weight
2051 readU16(&r); //fstype
2052 U16 magic = readU16(&r); //magicNumber
2053 /* we're being paranoid: it's entirely possible for the font
2054 size to be exactly 0x10000. Only treat this font as eot if
2055 it has the right magic number */
2056 if(magic == 0x4c50) {
2057 readU32(&r); //unicoderange[0]
2058 readU32(&r); //unicoderange[1]
2059 readU32(&r); //unicoderange[2]
2060 readU32(&r); //unicoderange[3]
2061 readU32(&r); //codepagerange[0]
2062 readU32(&r); //codepagerange[1]
2063 readU32(&r); //checksumadjustment
2064 readU32(&r); //reserved[0]
2065 readU32(&r); //reserved[1]
2066 readU32(&r); //reserved[2]
2067 readU32(&r); //reserved[3]
2068 readU16(&r); //padding
2071 for(nr=0;nr<4;nr++) {
2073 /* All of ttf is big-endian. All of ttf? No. One small eot table
2074 of indomitable little-endian... */
2076 len |= readU8(&r)<<8;
2078 for(t=0;t<len;t++) {
2079 U8 c = readU16(&r)>>8;
2081 readU16(&r); // zero terminator
2083 readU16(&r); // more padding
2085 /* adjust the offset to the start of the actual truetype
2086 data- the positions in the table header will be relative
2087 to the ttf data after the header, not to the file */
2091 ttf->version = readU32(&r);
2094 ttf->version = readU32(&r);
2098 if(ttf->version == TTCFTAG) {
2099 /* a ttc collection is a number of truetype fonts
2100 packaged together */
2102 msg("<error> Truncated TTC file (%d bytes)", length);
2105 U32 ttcf_version = readU32(&r); // 0x00000100: v1.0, 0x00000200: v2.0, includes DSIG table
2106 U32 num_fonts = readU32(&r); // number of fonts
2107 U32 font1_position = readU32(&r);
2108 if(font1_position+12 > length) {\
2109 msg("<error> Truncated TTC file (%d bytes, first font at %d)", length, font1_position);
2112 r.pos = font1_position;
2113 ttf->version = readU32(&r);
2116 int num_tables = readU16(&r);
2118 readU16(&r); //search range
2119 readU16(&r); //entry selector
2120 readU16(&r); //range shift
2122 if(num_tables*16 > length) {
2123 msg("<error> Truncated TTF file (table entries: %d)", num_tables);
2124 if(ttf->version != OPENTYPE &&
2125 ttf->version != TRUETYPE_MACOS &&
2126 ttf->version != VERSION_1_0) {
2127 // bad table length, weird version. This is probably not a ttf file.
2132 U32*table_data = malloc(16*num_tables);
2134 for(t=0;t<num_tables*4;t++) {
2135 table_data[t] = readU32(&r);
2137 for(t=0;t<num_tables;t++) {
2138 U32 tag = table_data[t*4];
2139 U32 checksum = table_data[t*4+1];
2140 U32 pos = table_data[t*4+2];
2141 U32 len = table_data[t*4+3];
2143 if(pos+len > length) {
2144 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);
2146 U8*mem = malloc(len);
2148 readBlock(&r, mem, len);
2150 ttf_table_t*table = ttf_addtable(ttf, tag);
2152 table->len = table->memsize = len;
2154 U32 checksum2 = ttf_table_checksum(table);
2155 if(checksum2!=checksum) {
2156 msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x",
2157 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
2158 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
2159 len, checksum2, checksum);
2166 if(!ttf_parse_tables(ttf))
2171 void ttf_create_truetype_tables(ttf_t*ttf)
2174 ttf->head = head_new(ttf);
2176 ttf->maxp = maxp_new(ttf);
2178 ttf->hea = hea_new(ttf);
2180 ttf->os2 = os2_new(ttf);
2182 ttf->post = post_new(ttf);
2184 ttf->gasp = gasp_new(ttf);
2186 ttf->prep = prep_new(ttf);
2189 ttf_table_t* ttf_write(ttf_t*ttf, U32*checksum_adjust)
2191 ttf_collapse_tables(ttf);
2193 ttf_table_t*file = ttf_table_new(0);
2194 writeU32(file, VERSION_1_0);
2196 /* write number of tables */
2198 ttf_table_t*t = ttf->tables;
2203 writeU16(file, num_tables);
2205 /* write search range */
2206 int tmp = num_tables;
2207 int search_range = 0;
2214 writeU16(file, search_range);
2216 /* write entry selector */
2217 int entry_selector = 0;
2222 writeU16(file, entry_selector);
2224 /* write range shift */
2225 int range_shift = num_tables*16 - search_range;
2226 writeU16(file, range_shift);
2228 /* write table dictionary */
2229 int table_dictionary_pos = file->len;
2230 int data_pos = file->len + num_tables*16;
2231 for(t=ttf->tables;t;t=t->next) {
2232 writeU32(file, t->id);
2233 writeU32(file, ttf_table_checksum(t));
2234 writeU32(file, data_pos);
2235 writeU32(file, t->len);
2237 data_pos += (-t->len)&3; //pad
2242 U8 zero[4]={0,0,0,0};
2243 for(t=ttf->tables;t;t=t->next) {
2244 if(t->id == TAG_HEAD)
2245 head_pos = file->len;
2246 writeBlock(file, t->data, t->len);
2247 writeBlock(file, zero, (-t->len)&3); //pad
2249 U32 checksum = 0xb1b0afba - ttf_table_checksum(file);
2251 *checksum_adjust = checksum;
2252 U8*checksum2 = file->data + head_pos + 8;
2253 checksum2[0] = checksum>>24;
2254 checksum2[1] = checksum>>16;
2255 checksum2[2] = checksum>>8;
2256 checksum2[3] = checksum>>0;
2260 ttf_table_t* ttf_eot_head(ttf_t*ttf)
2262 ttf_table_t*file = ttf_table_new(0);
2263 writeU32(file, 0); //file size (filled in later)
2264 writeU32(file, 0); //fontdatasize (filled in later)
2265 writeU32(file, 0x01000200);
2266 writeU32(file, 0); //flags
2267 writeU8(file, ttf->os2->panose_FamilyType);
2268 writeU8(file, ttf->os2->panose_SerifStyle);
2269 writeU8(file, ttf->os2->panose_Weight);
2270 writeU8(file, ttf->os2->panose_Proportion);
2271 writeU8(file, ttf->os2->panose_Contrast);
2272 writeU8(file, ttf->os2->panose_StrokeVariation);
2273 writeU8(file, ttf->os2->panose_ArmStyle);
2274 writeU8(file, ttf->os2->panose_Letterform);
2275 writeU8(file, ttf->os2->panose_Midline);
2276 writeU8(file, ttf->os2->panose_XHeight);
2277 writeU8(file, 1); //charset (default)
2278 writeU8(file, ttf->os2->fsSelection&1); //italic
2279 writeU32_LE(file, ttf->os2->usWeightClass);
2280 writeU16(file, 0); //fstype
2281 writeU16(file, 0x4c50); //magic
2282 writeU32_LE(file, ttf->os2->ulCharRange[0]);
2283 writeU32_LE(file, ttf->os2->ulCharRange[1]);
2284 writeU32_LE(file, ttf->os2->ulCharRange[2]);
2285 writeU32_LE(file, ttf->os2->ulCharRange[3]);
2286 writeU32_LE(file, ttf->os2->ulCodePageRange1);
2287 writeU32_LE(file, ttf->os2->ulCodePageRange2);
2288 writeU32(file, 0); //checksum adjust (filled in later)
2289 writeU32(file, 0); //reserved[0]
2290 writeU32(file, 0); //reserved[1]
2291 writeU32(file, 0); //reserved[2]
2292 writeU32(file, 0); //reserved[3]
2293 writeU16(file, 0); //padding(1)
2297 char* strings[] = {ttf->family_name, ttf->subfamily_name, ttf->version_string, ttf->full_name};
2298 int nr = sizeof(strings)/sizeof(strings[0]);
2301 char *string = strings[i];
2304 len = strlen(string);
2305 writeU16_LE(file, len*2);
2306 for(t=0;t<len;t++) {
2308 writeU8(file, string[t]);
2310 writeU16(file, 0); //zero byte pad
2313 writeU16(file, 0); //zero byte pad
2315 writeU16(file, 0); //padding(2)
2319 void ttf_save_eot(ttf_t*ttf, const char*filename)
2321 ttf_table_t* eot = ttf_eot_head(ttf);
2322 U32 checksum_adjust = 0;
2323 ttf_table_t* t = ttf_write(ttf, &checksum_adjust);
2325 U8*len_data = eot->data;
2326 U32 full_len = eot->len + t->len;
2327 len_data[0] = full_len>>0;
2328 len_data[1] = full_len>>8;
2329 len_data[2] = full_len>>16;
2330 len_data[3] = full_len>>24;
2332 U8*len_data2 = eot->data+4;
2333 len_data2[0] = t->len>>0;
2334 len_data2[1] = t->len>>8;
2335 len_data2[2] = t->len>>16;
2336 len_data2[3] = t->len>>24;
2338 U8*checksum_data = eot->data + 60;
2339 checksum_data[0] = checksum_adjust>>0;
2340 checksum_data[1] = checksum_adjust>>8;
2341 checksum_data[2] = checksum_adjust>>16;
2342 checksum_data[3] = checksum_adjust>>24;
2344 FILE*fi = fopen(filename, "wb");
2350 fwrite(eot->data, eot->len, 1, fi);
2351 fwrite(t->data, t->len, 1, fi);
2353 ttf_table_delete(0, t);
2354 ttf_table_delete(0, eot);
2357 void ttf_save(ttf_t*ttf, const char*filename)
2359 ttf_table_t* t = ttf_write(ttf, 0);
2360 FILE*fi = fopen(filename, "wb");
2365 fwrite(t->data, t->len, 1, fi);
2367 ttf_table_delete(0, t);
2370 void ttf_dump(ttf_t*ttf)
2372 msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
2373 ttf_table_t*table = ttf->tables;
2375 U32 tag = table->id;
2376 msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)",
2377 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
2378 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
2379 table = table->next;
2381 //ttf_table_dump(ttf_find_table(ttf, TAG_MAXP));
2389 void ttf_destroy_tables(ttf_t*ttf)
2391 ttf_table_t*table = ttf->tables;
2393 ttf_table_t*next = table->next;
2400 void ttf_reduce(ttf_t*ttf)
2402 ttf_destroy_tables(ttf);
2404 void ttf_destroy(ttf_t*ttf)
2406 ttf_destroy_tables(ttf);
2419 int main(int argn, const char*argv[])
2421 setConsoleLogging(7);
2422 const char*filename = "comic.ttf";
2425 //msg("<notice> Loading %s", filename);
2426 memfile_t*m = memfile_open(filename);
2427 ttf_t*ttf = ttf_load(m->data, m->len);
2430 msg("<error> Couldn't load %s", filename);
2435 ttf_create_truetype_tables(ttf);
2440 //printf("os2 version: %04x (%d), maxp size: %d\n",
2441 // ttf->os2->version, ttf->os2->size, ttf->maxp->size);
2442 ttf_save_eot(ttf, "testfont.eot");
2443 ttf_save(ttf, "testfont.ttf");