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
54 fpgm - assembly instructions
55 prep - assembly instructions
56 cvt - constant value table
57 gasp - gridfitting procedure
60 static U32 checksum_block(U8*_data, int len)
66 int len_minus_4 = len-4;
67 for(pos=0;pos<=len_minus_4;pos+=4) {
68 sum += data[pos]<<24|data[pos+1]<<16|data[pos+2]<<8|data[pos+3];
71 if(left == 1) sum+= data[pos+0]<<24;
72 if(left == 2) sum+= data[pos+0]<<24|data[pos+1]<<16;
73 if(left == 3) sum+= data[pos+0]<<24|data[pos+1]<<16|data[pos+2]<<8;
77 typedef struct _memreader {
83 static U8 readU8(memreader_t*r)
85 return r->mem[r->pos++];
87 static inline U16 readU16(memreader_t*r)
89 if(r->pos+2>r->size) return 0;
90 U16 val = r->mem[r->pos]<<8|
95 static S16 readS16(memreader_t*r)
97 return (S16)readU16(r);
99 static U32 readU32(memreader_t*r)
101 if(r->pos+4>r->size) return 0;
102 U32 val = r->mem[r->pos]<<24|
103 r->mem[r->pos+1]<<16|
109 static void readBlock(memreader_t*r, void*dest, int len)
111 int remaining = r->size-r->pos;
112 if(len > remaining) {
113 memcpy(dest, r->mem+r->pos, remaining);
114 memset(dest+remaining, 0, len - remaining);
117 memcpy(dest, r->mem+r->pos, len);
121 static void reader_reset(memreader_t*r)
125 #define INIT_READ(r,data,length,pos) memreader_t r = {(data),(pos),(length)};
127 static void expand(ttf_table_t*w, int newsize)
129 int v1 = (newsize+63)&~63;
130 int v2 = w->len + w->len / 2;
131 w->memsize = v1>v2?v1:v2;
132 w->data = rfx_realloc(w->data, w->memsize);
134 static inline void writeU8(ttf_table_t*w, unsigned char b)
136 if(w->memsize<w->len+1)
138 w->data[w->len++] = b;
140 static inline void writeU16(ttf_table_t*w, unsigned short v)
142 if(w->memsize<w->len+2)
144 w->data[w->len++] = v>>8;
145 w->data[w->len++] = v;
147 static inline void writeU16_LE(ttf_table_t*w, unsigned short v)
149 if(w->memsize<w->len+2)
151 w->data[w->len++] = v;
152 w->data[w->len++] = v>>8;
154 #define writeS16 writeU16
155 static inline void writeU32(ttf_table_t*w, unsigned long v)
157 if(w->memsize<w->len+4)
159 w->data[w->len++] = v>>24;
160 w->data[w->len++] = v>>16;
161 w->data[w->len++] = v>>8;
162 w->data[w->len++] = v;
164 static inline void writeU32_LE(ttf_table_t*w, unsigned long v)
166 if(w->memsize<w->len+4)
168 w->data[w->len++] = v;
169 w->data[w->len++] = v>>8;
170 w->data[w->len++] = v>>16;
171 w->data[w->len++] = v>>24;
173 static inline void writeBlock(ttf_table_t*w, void*data, int len)
175 if(w->memsize<w->len+len)
176 expand(w, w->len+len);
177 memcpy(w->data+w->len, data, len);
181 ttf_table_t*ttf_table_new(U32 id)
183 ttf_table_t*t = rfx_calloc(sizeof(ttf_table_t));
188 ttf_table_t*ttf_addtable(ttf_t*ttf, U32 id)
190 ttf_table_t*t = ttf_table_new(id);
192 ttf_table_t*before,*after=0;
193 for(before=ttf->tables; before&&before->id<id; before=before->next) {
196 if(before && before->id == id) {
197 msg("<error> Error: duplicate table %08x", id);
205 t->next = ttf->tables;
209 t->next = after->next;
216 ttf_table_t*ttf_find_table(ttf_t*ttf, U32 id)
218 ttf_table_t*table = ttf->tables;
226 void ttf_table_delete(ttf_t*ttf, ttf_table_t*table)
228 if(ttf && ttf->tables == table) {
229 ttf->tables = table->next;
232 table->prev->next = table->next;
234 table->next->prev = table->prev;
238 U32 ttf_table_checksum(ttf_table_t*t)
240 U32 checksum = checksum_block(t->data, t->len);
241 if(t->id==TAG_HEAD && t->len>=12) {
242 /* the checksum for the HEAD table is calculated by masking out
243 the checksumadjust field */
244 U32 adjust = t->data[8]<<24|t->data[9]<<16|t->data[10]<<8|t->data[11];
249 static U8 printable(U8 a)
251 if(a<32 || a==127) return '.';
254 static void hexdump(U8*data, int len, const char*prefix)
258 printf("%s -=> ",prefix);
260 printf("%02x ", data[t]);
261 ascii[t&15] = printable(data[t]);
262 if((t && ((t&15)==15)) || (t==len-1))
266 for(s=p-1;s<16;s++) {
270 printf(" %s\n", ascii);
272 printf(" %s\n%s -=> ",ascii,prefix);
276 static void ttf_table_dump(ttf_table_t*t, const char*prefix)
279 hexdump(t->data, t->len, prefix);
282 static table_head_t*head_new(ttf_t*ttf)
284 table_head_t*head = rfx_calloc(sizeof(table_head_t));
285 head->units_per_em = 1024;
287 if(ttf->num_glyphs) {
288 head->xmin = ttf->glyphs[0].xmin;
289 head->ymin = ttf->glyphs[0].ymin;
290 head->xmax = ttf->glyphs[0].xmax;
291 head->ymax = ttf->glyphs[0].ymax;
292 for(t=1;t<ttf->num_glyphs;t++) {
293 if(ttf->glyphs[t].xmin < head->xmin) head->xmin = ttf->glyphs[t].xmin;
294 if(ttf->glyphs[t].ymin < head->ymin) head->ymin = ttf->glyphs[t].ymin;
295 if(ttf->glyphs[t].xmax > head->xmax) head->xmax = ttf->glyphs[t].xmax;
296 if(ttf->glyphs[t].ymax > head->ymax) head->ymax = ttf->glyphs[t].ymax;
300 head->lowest_readable_size = 8; // not sure what font renderers actually do with this
304 static int head_parse(ttf_t*ttf, memreader_t*r)
306 ttf->head = rfx_calloc(sizeof(table_head_t));
307 U32 version = readU32(r);
308 if(version!=VERSION_1_0)
309 msg("<warning> Font HEAD has unknown version %08x", version);
310 U32 revision = readU32(r);
311 U32 checksum2 = readU32(r);
312 U32 magic = readU32(r);
313 if(magic!=0x5f0f3cf5)
314 msg("<warning> Font HEAD has unknown magic number %08x", magic);
315 ttf->head->flags = readU16(r);
316 ttf->head->units_per_em = readU16(r);
317 readU32(r);readU32(r); //created
318 readU32(r);readU32(r); //modified
319 ttf->head->xmin = readU16(r);
320 ttf->head->ymin = readU16(r);
321 ttf->head->xmax = readU16(r);
322 ttf->head->ymax = readU16(r);
323 ttf->head->macStyle = readU16(r);
324 ttf->head->lowest_readable_size = readU16(r); //in pixels
325 ttf->head->dir_hint = readS16(r);
326 int loc_index = readS16(r); //used in 'loca' table
328 msg("<warning> loca index format %d unknown", loc_index);
329 U16 glyph_data_format = readS16(r);
330 if(glyph_data_format!=0)
331 msg("<warning> Font glyph data format unknown: %04x", glyph_data_format);
332 if(r->pos < r->size) {
333 msg("<warning> Leftover bytes (%d) in HEAD tag", r->size - r->pos);
337 static void head_write(ttf_t*ttf, ttf_table_t*w, int loca_size)
339 writeU32(w, 0x10000);
340 writeU32(w, 0x10000);
341 writeU32(w, 0); //checksum
342 writeU32(w, 0x5f0f3cf5); //magic
343 writeU16(w, ttf->head->flags);
344 writeU16(w, ttf->head->units_per_em);
345 writeU32(w, 0);writeU32(w, 0); //created
346 writeU32(w, 0);writeU32(w, 0); //modified
347 writeU16(w, ttf->head->xmin);
348 writeU16(w, ttf->head->ymin);
349 writeU16(w, ttf->head->xmax);
350 writeU16(w, ttf->head->ymax);
351 writeU16(w, ttf->head->macStyle);
352 writeU16(w, ttf->head->lowest_readable_size);
353 writeS16(w, ttf->head->dir_hint);
354 writeS16(w, loca_size); //loca index size (32 bit)
355 writeS16(w, 0); //glyph data format
357 static void head_dump(ttf_t*ttf)
359 printf("head->flags: %d\n", ttf->head->flags);
360 printf("head->units_per_em: %d\n", ttf->head->units_per_em);
361 printf("head->xmin: %d\n", ttf->head->xmin);
362 printf("head->ymin: %d\n", ttf->head->ymin);
363 printf("head->xmax: %d\n", ttf->head->xmax);
364 printf("head->ymax: %d\n", ttf->head->ymax);
365 printf("head->macStyle: %d\n", ttf->head->macStyle);
366 printf("head->lowest_readable_size: %d\n", ttf->head->lowest_readable_size);
367 printf("head->dir_hint: %d\n", ttf->head->dir_hint);
369 static void head_delete(ttf_t*ttf)
377 static table_os2_t*os2_new(ttf_t*ttf)
379 table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
380 if(ttf->num_glyphs) {
383 for(t=0;t<ttf->num_glyphs;t++) {
384 average_width += (ttf->glyphs[t].advance + ttf->glyphs[t].bearing);
386 os2->xAvgCharWidth = average_width / ttf->num_glyphs;
389 /* that's what everybody seems to fill in */
390 os2->usWeightClass = 400;
391 os2->usWidthClass = 5;
394 int advance = (ttf->head->xmax - ttf->head->xmin)/2;
395 int height = (ttf->head->xmax - ttf->head->xmin);
397 /* I do believe a sane font rendering engine will actually use
398 the font advance here- the subscript/superscript position will
399 not be the same for each glyph */
400 os2->ySuperscriptXSize = os2->ySubscriptXSize = (ttf->head->xmax - ttf->head->xmin)/2;
401 os2->ySuperscriptYSize = os2->ySubscriptYSize = (ttf->head->ymax - ttf->head->ymin)/2;
402 os2->ySubscriptXOffset = advance;
403 os2->ySubscriptYOffset = 0;
404 os2->ySuperscriptXOffset = advance;
405 os2->ySuperscriptYOffset = (ttf->head->ymax - ttf->head->ymin)/2;
406 os2->yStrikeoutSize = ttf->head->units_per_em / 10;
407 os2->yStrikeoutPosition = ymid;
408 os2->usWinAscent = ttf->head->ymax>0?ttf->head->ymax:0;
409 os2->usWinDescent = ttf->head->ymin<0?-ttf->head->ymin:0;
410 os2->sxHeight = ymid;
411 os2->sCapHeight = height*2/3;
413 os2->panose_Weight = 4;
415 /* strictly speaking we'd have to set 92/64 bits in these tables, depending on
416 what parts of the unicode table is filled. (e.g. bit 90 = tibetan). */
417 os2->ulCharRange[0] = 1;
418 os2->ulCharRange[1] = 0;
419 os2->ulCharRange[2] = 0;
420 os2->ulCharRange[3] = 0;
421 os2->ulCodePageRange1 = 1;
422 os2->ulCodePageRange2 = 0;
424 if(ttf->unicode_size) {
426 for(min=0;min<ttf->unicode_size;min++)
427 if(ttf->unicode[min]) break;
428 for(max=ttf->unicode_size-1;max>=0;max--)
429 if(ttf->unicode[max]) break;
431 os2->fsFirstCharIndex = min;
432 os2->fsLastCharIndex = max;
435 os2->sTypoAscender = ttf->ascent;
436 os2->sTypoDescender = ttf->descent;
437 os2->sTypoLineGap = ttf->lineGap;
439 os2->usDefaultChar = 0;
440 os2->usBreakChar = (ttf->unicode_size>0x20 && ttf->unicode[0x20])?0x20:0;
441 os2->usMaxContext = 0; // we don't use ligatures yet
444 static table_os2_t*os2_parse(memreader_t*r)
446 table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
447 U16 version = readU16(r);
452 if(version!=0 && version!=1 && version!=2 && version!=3)
453 msg("<warning> Unknown OS2 version: %04x", version);
454 os2->xAvgCharWidth = readS16(r);
455 os2->usWeightClass = readU16(r);
456 os2->usWidthClass = readU16(r);
458 os2->ySubscriptXSize = readU16(r);
459 os2->ySubscriptYSize = readU16(r);
460 os2->ySubscriptXOffset = readU16(r);
461 os2->ySubscriptYOffset = readU16(r);
462 os2->ySuperscriptXSize = readU16(r);
463 os2->ySuperscriptYSize = readU16(r);
464 os2->ySuperscriptXOffset = readU16(r);
465 os2->ySuperscriptYOffset = readU16(r);
466 os2->yStrikeoutSize = readU16(r);
467 os2->yStrikeoutPosition = readU16(r);
468 os2->sFamilyClass = readU16(r);
469 os2->panose_FamilyType = readU8(r);
470 os2->panose_SerifStyle = readU8(r);
471 os2->panose_Weight = readU8(r);
472 os2->panose_Proportion = readU8(r);
473 os2->panose_Contrast = readU8(r);
474 os2->panose_StrokeVariation = readU8(r);
475 os2->panose_ArmStyle = readU8(r);
476 os2->panose_Letterform = readU8(r);
477 os2->panose_Midline = readU8(r);
478 os2->panose_XHeight = readU8(r);
479 os2->ulCharRange[0] = readU32(r);
480 os2->ulCharRange[1] = readU32(r);
481 os2->ulCharRange[2] = readU32(r);
482 os2->ulCharRange[3] = readU32(r);
484 os2->fsSelection = readU16(r);
485 os2->fsFirstCharIndex = readU16(r);
486 os2->fsLastCharIndex = readU16(r);
487 os2->sTypoAscender = readS16(r);
488 os2->sTypoDescender = readS16(r);
489 os2->sTypoLineGap = readS16(r);
490 os2->usWinAscent = readU16(r);
491 os2->usWinDescent = readU16(r);
492 if(version<1) return os2;
493 os2->ulCodePageRange1 = readU32(r);
494 os2->ulCodePageRange2 = readU32(r);
495 if(version<2) return os2;
496 os2->sxHeight = readS16(r);
497 os2->sCapHeight = readS16(r);
498 os2->usDefaultChar = readU16(r);
499 os2->usBreakChar = readU16(r);
500 os2->usMaxContext = readU16(r);
502 if(r->pos < r->size) {
503 msg("<warning> Leftover bytes (%d) in OS2 tag", r->size - r->pos);
507 static void os2_write(ttf_t*ttf, ttf_table_t*w)
509 table_os2_t*os2 = ttf->os2;
511 if(os2->sxHeight|os2->sCapHeight|os2->usDefaultChar|os2->usBreakChar|os2->usMaxContext) {
514 writeU16(w, version);
515 writeS16(w, os2->xAvgCharWidth);
516 writeU16(w, os2->usWeightClass);
517 writeU16(w, os2->usWidthClass);
518 writeU16(w, 0); //fstype
519 writeU16(w, os2->ySubscriptXSize);
520 writeU16(w, os2->ySubscriptYSize);
521 writeU16(w, os2->ySubscriptXOffset);
522 writeU16(w, os2->ySubscriptYOffset);
523 writeU16(w, os2->ySuperscriptXSize);
524 writeU16(w, os2->ySuperscriptYSize);
525 writeU16(w, os2->ySuperscriptXOffset);
526 writeU16(w, os2->ySuperscriptYOffset);
527 writeU16(w, os2->yStrikeoutSize);
528 writeU16(w, os2->yStrikeoutPosition);
529 writeU16(w, os2->sFamilyClass);
530 writeU8(w, os2->panose_FamilyType);
531 writeU8(w, os2->panose_SerifStyle);
532 writeU8(w, os2->panose_Weight);
533 writeU8(w, os2->panose_Proportion);
534 writeU8(w, os2->panose_Contrast);
535 writeU8(w, os2->panose_StrokeVariation);
536 writeU8(w, os2->panose_ArmStyle);
537 writeU8(w, os2->panose_Letterform);
538 writeU8(w, os2->panose_Midline);
539 writeU8(w, os2->panose_XHeight);
540 writeU32(w, os2->ulCharRange[0]);
541 writeU32(w, os2->ulCharRange[1]);
542 writeU32(w, os2->ulCharRange[2]);
543 writeU32(w, os2->ulCharRange[3]);
544 writeU32(w, 0x53434244); //vendor
545 writeU16(w, os2->fsSelection);
546 writeU16(w, os2->fsFirstCharIndex);
547 writeU16(w, os2->fsLastCharIndex);
548 writeS16(w, os2->sTypoAscender);
549 writeS16(w, os2->sTypoDescender);
550 writeS16(w, os2->sTypoLineGap);
551 writeU16(w, os2->usWinAscent);
552 writeU16(w, os2->usWinDescent);
553 if(version<1) return;
554 writeU32(w, os2->ulCodePageRange1);
555 writeU32(w, os2->ulCodePageRange2);
556 if(version<2) return;
557 writeS16(w, os2->sxHeight);
558 writeS16(w, os2->sCapHeight);
559 writeU16(w, os2->usDefaultChar);
560 writeU16(w, os2->usBreakChar);
561 writeU16(w, os2->usMaxContext);
563 static void os2_dump(ttf_t*ttf)
565 table_os2_t*os2 = ttf->os2;
567 printf("os2->xAvgCharWidth: %d\n", os2->xAvgCharWidth);
568 printf("os2->usWeightClass: %d\n", os2->usWeightClass);
569 printf("os2->usWidthClass: %d\n", os2->usWidthClass);
570 printf("os2->ySubscriptXSize: %d\n", os2->ySubscriptXSize);
571 printf("os2->ySubscriptYSize: %d\n", os2->ySubscriptYSize);
572 printf("os2->ySubscriptXOffset: %d\n", os2->ySubscriptXOffset);
573 printf("os2->ySubscriptYOffset: %d\n", os2->ySubscriptYOffset);
574 printf("os2->ySuperscriptXSize: %d\n", os2->ySuperscriptXSize);
575 printf("os2->ySuperscriptYSize: %d\n", os2->ySuperscriptYSize);
576 printf("os2->ySuperscriptXOffset: %d\n", os2->ySuperscriptXOffset);
577 printf("os2->ySuperscriptYOffset: %d\n", os2->ySuperscriptYOffset);
578 printf("os2->yStrikeoutSize: %d\n", os2->yStrikeoutSize);
579 printf("os2->yStrikeoutPosition: %d\n", os2->yStrikeoutPosition);
580 printf("os2->sFamilyClass: %d\n", os2->sFamilyClass);
581 printf("os2->panose_FamilyType: %d\n", os2->panose_FamilyType);
582 printf("os2->panose_SerifStyle: %d\n", os2->panose_SerifStyle);
583 printf("os2->panose_Weight: %d\n", os2->panose_Weight);
584 printf("os2->panose_Proportion: %d\n", os2->panose_Proportion);
585 printf("os2->panose_Contrast: %d\n", os2->panose_Contrast);
586 printf("os2->panose_StrokeVariation: %d\n", os2->panose_StrokeVariation);
587 printf("os2->panose_ArmStyle: %d\n", os2->panose_ArmStyle);
588 printf("os2->panose_Letterform: %d\n", os2->panose_Letterform);
589 printf("os2->panose_Midline: %d\n", os2->panose_Midline);
590 printf("os2->panose_XHeight: %d\n", os2->panose_XHeight);
591 printf("os2->ulCharRange[0]: %d\n", os2->ulCharRange[0]);
592 printf("os2->ulCharRange[1]: %d\n", os2->ulCharRange[1]);
593 printf("os2->ulCharRange[2]: %d\n", os2->ulCharRange[2]);
594 printf("os2->ulCharRange[3]: %d\n", os2->ulCharRange[3]);
595 printf("os2->fsSelection: %d\n", os2->fsSelection);
596 printf("os2->fsFirstCharIndex: %d\n", os2->fsFirstCharIndex);
597 printf("os2->fsLastCharIndex: %d\n", os2->fsLastCharIndex);
598 printf("os2->sTypoAscender: %d\n", os2->sTypoAscender);
599 printf("os2->sTypoDescender: %d\n", os2->sTypoDescender);
600 printf("os2->sTypoLineGap: %d\n", os2->sTypoLineGap);
601 printf("os2->usWinAscent: %d\n", os2->usWinAscent);
602 printf("os2->usWinDescent: %d\n", os2->usWinDescent);
603 printf("os2->ulCodePageRange1: %d\n", os2->ulCodePageRange1);
604 printf("os2->ulCodePageRange2: %d\n", os2->ulCodePageRange2);
605 printf("os2->sxHeight: %d\n", os2->sxHeight);
606 printf("os2->sCapHeight: %d\n", os2->sCapHeight);
607 printf("os2->usDefaultChar: %d\n", os2->usDefaultChar);
608 printf("os2->usBreakChar: %d\n", os2->usBreakChar);
609 printf("os2->usMaxContext: %d\n", os2->usMaxContext);
611 static void os2_delete(ttf_t*ttf)
618 static table_maxp_t*maxp_new(ttf_t*ttf)
620 table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
623 if(ttf->num_glyphs) {
625 for(t=0;t<ttf->num_glyphs;t++) {
626 if(ttf->glyphs[t].num_points>max)
627 max = ttf->glyphs[t].num_points;
630 for(s=0;s<ttf->glyphs[t].num_points;s++) {
631 if(ttf->glyphs[t].points[s].flags&GLYPH_CONTOUR_END)
634 if(maxp->maxContours < contours)
635 maxp->maxContours = contours;
637 maxp->maxPoints = max;
639 /* we don't generate composite glyphs yet */
640 maxp->maxComponentPoints = 0;
641 maxp->maxComponentContours = 0;
645 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
647 U32 version = readU32(r);
648 ttf->num_glyphs = readU16(r);
649 /* according to freetype, older fonts (version<0x10000)
650 apparently only contain the number of glyphs. this is
651 rather rare, though. */
652 if(version<0x10000 && r->size==6) return 0;
655 msg("<warning> Truncated maxp table (version %d)", version);
657 table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
658 maxp->maxPoints = readU16(r);
659 maxp->maxContours = readU16(r);
660 maxp->maxComponentPoints = readU16(r);
661 maxp->maxComponentContours = readU16(r);
662 maxp->maxZones = readU16(r);
663 maxp->maxTwilightPoints = readU16(r);
664 maxp->maxStorage = readU16(r);
665 maxp->maxFunctionDefs = readU16(r);
666 maxp->maxInstructionDefs = readU16(r);
667 maxp->maxStackElements = readU16(r);
668 maxp->maxSizeOfInstructions = readU16(r);
669 maxp->maxComponentElements = readU16(r);
670 maxp->maxComponentDepth = readU16(r);
673 static void maxp_write(ttf_t*ttf, ttf_table_t*w)
675 table_maxp_t*maxp = ttf->maxp;
677 /* version 0.5 simplified maxp table */
678 writeU32(w, 0x00005000);
679 writeU16(w, ttf->num_glyphs);
682 writeU32(w, 0x10000); //version
683 writeU16(w, ttf->num_glyphs);
684 writeU16(w, maxp->maxPoints);
685 writeU16(w, maxp->maxContours);
686 writeU16(w, maxp->maxComponentPoints);
687 writeU16(w, maxp->maxComponentContours);
688 writeU16(w, maxp->maxZones);
689 writeU16(w, maxp->maxTwilightPoints);
690 writeU16(w, maxp->maxStorage);
691 writeU16(w, maxp->maxFunctionDefs);
692 writeU16(w, maxp->maxInstructionDefs);
693 writeU16(w, maxp->maxStackElements);
694 writeU16(w, maxp->maxSizeOfInstructions);
695 writeU16(w, maxp->maxComponentElements);
696 writeU16(w, maxp->maxComponentDepth);
698 static void maxp_dump(ttf_t*ttf)
700 table_maxp_t*maxp = ttf->maxp;
702 printf("maxp->maxPoints: %d\n", maxp->maxPoints);
703 printf("maxp->maxContours: %d\n", maxp->maxContours);
704 printf("maxp->maxComponentPoints: %d\n", maxp->maxComponentPoints);
705 printf("maxp->maxComponentContours: %d\n", maxp->maxComponentContours);
706 printf("maxp->maxZones: %d\n", maxp->maxZones);
707 printf("maxp->maxTwilightPoints: %d\n", maxp->maxTwilightPoints);
708 printf("maxp->maxStorage: %d\n", maxp->maxStorage);
709 printf("maxp->maxFunctionDefs: %d\n", maxp->maxFunctionDefs);
710 printf("maxp->maxInstructionDefs: %d\n", maxp->maxInstructionDefs);
711 printf("maxp->maxStackElements: %d\n", maxp->maxStackElements);
712 printf("maxp->maxSizeOfInstructions: %d\n", maxp->maxSizeOfInstructions);
713 printf("maxp->maxComponentElements: %d\n", maxp->maxComponentElements);
714 printf("maxp->maxComponentDepth: %d\n", maxp->maxComponentDepth);
716 static void maxp_delete(ttf_t*ttf)
723 static table_hea_t*hea_new(ttf_t*ttf)
725 table_hea_t*hea = rfx_calloc(sizeof(table_hea_t));
726 if(ttf->num_glyphs) {
728 for(t=0;t<ttf->num_glyphs;t++) {
729 if(ttf->glyphs[t].advance > hea->advanceWidthMax)
730 hea->advanceWidthMax = ttf->glyphs[t].advance;
731 if(ttf->glyphs[t].xmin < hea->minLeftSideBearing)
732 hea->minLeftSideBearing = ttf->glyphs[t].xmin;
733 if(ttf->glyphs[t].xmax < hea->minRightSideBearing)
734 hea->minRightSideBearing = ttf->glyphs[t].xmax;
735 int width = ttf->glyphs[t].xmax - ttf->glyphs[t].xmin;
736 if(width > hea->xMaxExtent)
737 hea->xMaxExtent = width;
739 hea->caretSlopeRise = 1;
743 static int hea_parse(memreader_t*r, ttf_t*ttf)
745 table_hea_t*hea = ttf->hea = rfx_calloc(sizeof(table_hea_t));
746 U32 version = readU32(r);
747 ttf->ascent = readS16(r);
748 ttf->descent = readS16(r);
749 ttf->lineGap = readS16(r);
750 hea->advanceWidthMax = readU16(r);
751 hea->minLeftSideBearing = readS16(r);
752 hea->minRightSideBearing = readS16(r);
753 hea->xMaxExtent = readS16(r);
754 hea->caretSlopeRise = readS16(r);
755 hea->caretSlopeRun = readS16(r);
756 hea->caretOffset = readS16(r);
757 readS16(r); //reserved[0]
758 readS16(r); //reserved[1]
759 readS16(r); //reserved[2]
760 readS16(r); //reserved[3]
761 S16 metricDataFormat = readS16(r); //should be 0
762 if(metricDataFormat!=0) {
763 msg("<warning> Unknown metric format %d", metricDataFormat);
765 int num_advances = readU16(r);
766 if(num_advances > ttf->num_glyphs) {
767 msg("<warning> bad number of horizontal metrics: %d", num_advances);
768 num_advances = ttf->num_glyphs;
772 static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances)
774 table_hea_t*hea = ttf->hea;
775 writeU32(w, 0x00010000);
776 writeS16(w, ttf->ascent);
777 writeS16(w, ttf->descent);
778 writeS16(w, ttf->lineGap);
779 writeU16(w, hea->advanceWidthMax);
780 writeS16(w, hea->minLeftSideBearing);
781 writeS16(w, hea->minRightSideBearing);
782 writeS16(w, hea->xMaxExtent);
783 writeS16(w, hea->caretSlopeRise);
784 writeS16(w, hea->caretSlopeRun);
785 writeS16(w, hea->caretOffset);
786 writeS16(w, 0); //reserved
787 writeS16(w, 0); //reserved
788 writeS16(w, 0); //reserved
789 writeS16(w, 0); //reserved
790 writeS16(w, 0); //metricDataFormat
791 writeU16(w, num_advances);
794 static void hea_dump(ttf_t*ttf)
796 table_hea_t*hea = ttf->hea;
798 const char*dir = ttf->is_vertical?"v":"h";
799 printf("%shea->ascent: %d\n", dir, ttf->ascent);
800 printf("%shea->descent: %d\n", dir, ttf->descent);
801 printf("%shea->lineGap: %d\n", dir, ttf->lineGap);
802 printf("%shea->advanceWidthMax: %d\n", dir, hea->advanceWidthMax);
803 printf("%shea->minLeftSideBearing: %d\n", dir, hea->minLeftSideBearing);
804 printf("%shea->minRightSideBearing: %d\n", dir, hea->minRightSideBearing);
805 printf("%shea->xMaxExtent: %d\n", dir, hea->xMaxExtent);
806 printf("%shea->caretSlopeRise: %d\n", dir, hea->caretSlopeRise);
807 printf("%shea->caretSlopeRun: %d\n", dir, hea->caretSlopeRun);
808 printf("%shea->caretOffset: %d\n", dir, hea->caretOffset);
810 static void hea_delete(ttf_t*ttf)
818 static void mtx_parse(memreader_t*r, ttf_t*ttf, int num_advances)
822 if(num_advances > r->size/4)
823 num_advances = r->size/4;
824 for(t=0;t<num_advances;t++) {
825 old_advance = ttf->glyphs[t].advance = readU16(r);
826 ttf->glyphs[t].bearing = readS16(r);
828 int rest = (r->size - num_advances*4)/2;
829 if(ttf->num_glyphs < num_advances+rest) {
830 rest = ttf->num_glyphs-num_advances;
832 for(t=0;t<rest;t++) {
833 ttf->glyphs[t].advance = old_advance;
834 ttf->glyphs[t].bearing = readS16(r);
837 static int mtx_write(ttf_t*ttf, ttf_table_t*w)
839 int num_advances = ttf->num_glyphs;
840 if(ttf->num_glyphs>=2) {
842 for(t=ttf->num_glyphs-1;t>0;t--) {
843 if(ttf->glyphs[t-1].advance !=
844 ttf->glyphs[t].advance) break;
846 /* we need to store all individual advances as well
847 as one entry for the constant */
852 for(t=0;t<num_advances;t++) {
853 writeU16(w, ttf->glyphs[t].advance);
854 writeU16(w, ttf->glyphs[t].bearing);
856 for(;t<ttf->num_glyphs;t++) {
857 writeU16(w, ttf->glyphs[t].bearing);
862 static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size)
865 int num = ttf->num_glyphs+1;
866 U32*locations = rfx_calloc(num*sizeof(U32));
869 char warn_unsorted = 1;
871 if(num*4 > r->size) {
872 msg("<warning> Short 'loca' table (32 bit): %d/%d", r->size/4, num);
875 if(num*4 < r->size) {
876 msg("<warning> Extraneous data (%d bytes) in 'loca' table (32 bit)", r->size-num*4);
879 locations[t] = loc = readU32(r);
880 if(lastloc > loc && warn_unsorted) {
881 msg("<warning> Unsorted 'loca' table (32 bit)");
887 if(num*2 > r->size) {
888 msg("<warning> Short 'loca' table (16 bit)");
891 if(num*2 < r->size) {
892 msg("<warning> Extraneous data (%d bytes) in 'loca' table (16 bit)", r->size-num*2);
895 locations[t] = loc = readU16(r)*2;
896 if(lastloc > loc && warn_unsorted) {
897 msg("<warning> Unsorted 'loca' table");
905 static int loca_write(ttf_t*ttf, ttf_table_t*w, U32*locations)
909 for(t=0;t<=ttf->num_glyphs;t++) {
910 if(locations[t]>=0x20000 || (locations[t]&1)) {
917 for(t=0;t<=ttf->num_glyphs;t++) {
918 writeU32(w, locations[t]);
922 for(t=0;t<=ttf->num_glyphs;t++) {
923 writeU16(w, locations[t]/2);
929 static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int glyphnr)
931 ttfglyph_t*glyph = &ttf->glyphs[glyphnr];
935 endpoints = malloc(sizeof(U16)*num_contours);
938 for(s=0;s<num_contours;s++) {
939 int pos = endpoints[s] = readU16(r);
941 msg("<warning> Unsorted endpoints array (len:%d) last=%d now=%d", s, pos, lastpos);
946 U16 code_len = readU16(r);
948 glyph->code = malloc(sizeof(U16)*code_len);
949 readBlock(r, glyph->code, code_len);
950 glyph->code_size = code_len;
956 /*msg("<notice> TTF Glyph %d) code_size=%d num_contours=%d glyph->num_points=%d %d/%d/%d/%d",
957 glyphnr, code_len, num_contours, glyph->num_points,
958 xmin, ymin, xmax, ymax);*/
959 INIT_READ(fx, r->mem, r->size, r->pos);
960 INIT_READ(fy, r->mem, r->size, r->pos);
962 glyph->num_points = endpoints[num_contours-1] + 1;
963 glyph->points = rfx_calloc(sizeof(ttfpoint_t)*glyph->num_points);
965 /* parse flag array (1st pass- to determine start of coordinates) */
967 while(num<glyph->num_points) {
970 msg("<error> Bad flags in glyph outline: %02x (at pos %d)", flag, num);
973 glyph->num_points = 0;
979 if(count+num>glyph->num_points) {
980 msg("<warning> Bad count (%d) in glyph (%d) (at pos %d)", count, glyphnr, num);
981 count = glyph->num_points-num;
986 /* parse flag array (2nd pass) and x coordinates */
991 int bytepos = r->pos;
992 while(num<glyph->num_points) {
993 U8 flag = readU8(&fx);
994 int count = flag&8?readU8(&fx)+1:1;
995 count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
998 if(contour_pos<num_contours && num==endpoints[contour_pos]) {
1003 if((flag&0x12) == 0x12) x += readU8(r);
1004 else if((flag&0x12) == 0x02) x -= readU8(r);
1005 else if((flag&0x12) == 0x00) x += readS16(r);
1007 glyph->points[num].x = x;
1008 U8 f = flag&GLYPH_ON_CURVE;
1009 if(is_start) f|=GLYPH_CONTOUR_START;
1010 if(is_end) f|=GLYPH_CONTOUR_END;
1011 glyph->points[num].flags = f;
1017 /* parse flag array (3rd pass) and y coordinates */
1020 while(num<glyph->num_points) {
1021 U8 flag = readU8(&fy);
1022 int count = flag&8?readU8(&fy)+1:1;
1023 count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
1025 if((flag&0x24) == 0x24) y += readU8(r);
1026 else if((flag&0x24) == 0x04) y -= readU8(r);
1027 else if((flag&0x24) == 0x00) y += readS16(r);
1028 glyph->points[num].y = y;
1035 static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
1038 char warn_about_compound_glyphs=0;
1039 for(t=0;t<ttf->num_glyphs;t++) {
1040 INIT_READ(r, rr->mem, rr->size, loca[t]);
1041 if(loca[t]==loca[t+1] || loca[t]==r.size)
1042 continue; //empty glyph
1043 if(r.pos+10>r.size) {
1044 msg("<warning> Truncated glyph entry %d/%d (or bad loca entry %d/%d, next loca: %d)",
1045 t, ttf->num_glyphs, loca[t], r.size, loca[t+1]);
1048 S16 num_contours = readS16(&r);
1049 ttf->glyphs[t].xmin = readS16(&r);
1050 ttf->glyphs[t].ymin = readS16(&r);
1051 ttf->glyphs[t].xmax = readS16(&r);
1052 ttf->glyphs[t].ymax = readS16(&r);
1054 if(num_contours<0) {
1055 if(warn_about_compound_glyphs)
1056 msg("<error> Compound glyphs not supported yet");
1057 warn_about_compound_glyphs=0;
1059 if(!parse_simple_glyph(ttf, &r, num_contours, t))
1065 void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
1067 /* endpoints array */
1069 for(s=0;s<g->num_points;s++) {
1070 if(g->points[s].flags&GLYPH_CONTOUR_END)
1075 writeU16(w, g->code_size);
1077 writeBlock(w, g->code, g->code_size);
1084 for(s=0;s<g->num_points;s++) {
1085 ttfpoint_t*p = &g->points[s];
1086 int dx = p->x - lastx;
1087 int dy = p->y - lasty;
1088 U8 flags = p->flags&GLYPH_ON_CURVE;
1091 } else if(dx<0 && dx>=-255) {
1093 } else if(dx>0 && dx<=255) {
1098 } else if(dy<0 && dy>=-255) {
1100 } else if(dy>0 && dy<=255) {
1103 if(flags == lastflag && flagcount<255) {
1108 writeU8(w, lastflag|8);
1109 writeU8(w, flagcount);
1111 writeU8(w, lastflag);
1122 writeU8(w, lastflag|8);
1123 writeU8(w, flagcount);
1125 writeU8(w, lastflag);
1130 int bytepos = w->len;
1131 for(s=0;s<g->num_points;s++) {
1132 ttfpoint_t*p = &g->points[s];
1133 int dx = p->x - lastx;
1134 if(dx>32767 || dx<-32768) {
1135 msg("<error> Coordinate overflow in glyph");
1138 if(dx>0 && dx<=255) writeU8(w, dx);
1139 else if(dx<0 && dx>=-255) writeU8(w, -dx);
1140 else if(dx) writeS16(w, dx);
1144 for(s=0;s<g->num_points;s++) {
1145 ttfpoint_t*p = &g->points[s];
1146 int dy = p->y - lasty;
1147 if(dy>32767 || dy<-32768) {
1148 msg("<error> Coordinate overflow in glyph");
1151 if(dy>0 && dy<=255) writeU8(w, dy);
1152 else if(dy<0 && dy>=-255) writeU8(w, -dy);
1153 else if(dy) writeS16(w, dy);
1156 U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
1158 U32*locations = malloc(sizeof(U32)*(ttf->num_glyphs+1));
1160 for(t=0;t<ttf->num_glyphs;t++) {
1161 locations[t] = w->len;
1162 ttfglyph_t*g = &ttf->glyphs[t];
1164 int num_contours = 0;
1165 for(s=0;s<g->num_points;s++) {
1166 if(g->points[s].flags&GLYPH_CONTOUR_END)
1169 writeS16(w, num_contours?num_contours:1);
1170 writeS16(w, g->xmin);
1171 writeS16(w, g->ymin);
1172 writeS16(w, g->xmax);
1173 writeS16(w, g->ymax);
1176 /* some ttf parsers can't deal with zero contours, so in the case
1177 of an empty glyph, write a single point (0,0) */
1178 writeU16(w, 0); //endpoint of 1st contour
1179 writeU16(w, g->code_size);
1181 writeBlock(w, g->code, g->code_size);
1182 writeU8(w, 0x31); //flag (xy=(0,0),on curve)
1184 write_simple_glyph(w, g);
1187 locations[t] = w->len;
1190 void glyf_dump(ttf_t* ttf)
1192 if(!ttf->glyphs) return;
1194 for(t=0;t<ttf->num_glyphs;t++) {
1195 ttfglyph_t*g = &ttf->glyphs[t];
1196 printf("glyph %d)\n", t);
1197 printf(" advance=%d\n", g->advance);
1198 printf(" bearing=%d\n", g->bearing);
1199 printf(" bbox=(%d/%d/%d/%d)\n", g->xmin, g->ymin, g->xmax, g->ymax);
1200 printf(" points=(");
1202 for(s=0;s<g->num_points;s++) {
1204 printf("%d/%d/0x%02x", g->points[s].x, g->points[s].y, g->points[s].flags);
1208 hexdump(g->code, g->code_size, " ");
1211 void glyf_delete(ttf_t* ttf)
1216 for(t=0;t<ttf->num_glyphs;t++) {
1217 if(ttf->glyphs[t].code) {
1218 free(ttf->glyphs[t].code);
1219 ttf->glyphs[t].code = 0;
1221 if(ttf->glyphs[t].points) {
1222 free(ttf->glyphs[t].points);
1223 ttf->glyphs[t].points = 0;
1226 free(ttf->glyphs);ttf->glyphs=0;
1229 static void grow_unicode(ttf_t*ttf, int index)
1233 ttf->unicode = rfx_calloc(sizeof(ttf->unicode[0])*size);
1234 } else if(ttf->unicode_size<size) {
1235 ttf->unicode = rfx_realloc(ttf->unicode, sizeof(ttf->unicode[0])*size);
1236 memset(ttf->unicode+ttf->unicode_size, 0, sizeof(ttf->unicode[0])*(size - ttf->unicode_size));
1238 ttf->unicode_size = size;
1240 void cmap_parse(memreader_t*r, ttf_t*ttf)
1242 readU16(r); // version (0)
1243 int num_subtables = readU16(r);
1246 if(r->pos+num_subtables*8 > r->size) {
1247 msg("<warning> CMap overflow");
1248 num_subtables = (r->size-r->pos)/8;
1251 for(t=0;t<num_subtables;t++) {
1252 U16 platform = readU16(r);
1253 U16 encoding = readU16(r);
1254 U32 offset = readU32(r);
1255 if(offset>r->size) {
1256 msg("<warning> CMAP table %d %d is out of bounds (%d)", platform, encoding, offset);
1260 int is_unicode = platform==0 ||
1261 platform==3 && encoding == 1 ||
1262 platform==3 && encoding == 10;
1267 INIT_READ(t, r->mem, r->size, offset);
1268 U16 format = readU16(&t);
1269 int length = readU16(&t);
1270 U16 language = readU16(&t);
1273 msg("<warning> Language code %02x in unicode mapping", language);
1278 if(t.pos+length > t.size) {
1279 msg("<warning> overflow in format 0 cmap table");
1282 data = malloc(num*sizeof(unicode_t));
1284 grow_unicode(ttf, num);
1285 for(s=0;s<num;s++) {
1286 ttf->unicode[s] = readU8(&t);
1288 } else if(format == 4) {
1289 U16 segment_count = readU16(&t);
1290 if(segment_count&1) {
1291 msg("<error> Bad segmentx2 count %d", segment_count);
1295 readU16(&t); //searchrange
1296 readU16(&t); //entry selector
1297 readU16(&t); //range shift
1298 INIT_READ(r_end, t.mem, t.size, t.pos);
1299 INIT_READ(r_start, t.mem, t.size, t.pos+2+segment_count*2);
1300 INIT_READ(r_delta, t.mem, t.size, t.pos+2+segment_count*4);
1301 INIT_READ(r_range, t.mem, t.size, t.pos+2+segment_count*6);
1302 int glyphmap_start = t.pos+2+segment_count*8;
1303 int glyphmap_size = t.size - glyphmap_start;
1305 for(s=0;s<segment_count;s++) {
1306 U16 start = readU16(&r_start);
1307 U16 end = readU16(&r_end);
1308 U16 delta = readU16(&r_delta);
1309 U16 range = readU16(&r_range);
1310 if(start==0xffff && end==0xffff && delta==1) {
1311 /* this is a common (maybe even required) occurence in fonts
1312 which explicitly map "unicode undefined" (0xffff) to
1313 "glyph undefined" (0).
1314 We don't want to blow our unicode table up to 65536 just
1315 because of this, so ignore this entry.
1319 grow_unicode(ttf, end);
1322 for(u=start;u<=end;u++) {
1323 ttf->unicode[u] = (u + delta) & 0xffff;
1326 int pos = r_range.pos-2+range;
1327 if(warn && pos+end-start+1 > t.size) {
1328 msg("<warning> glyphmap index out of bounds (%d-%d/%d)", pos, pos+end-start, t.size);
1331 INIT_READ(g, t.mem, t.size, pos);
1332 for(u=start;u<=end;u++) {
1333 ttf->unicode[u] = readU16(&g);
1340 static int segment_size(unicode_t*unicode, int pos, int size)
1344 for(s=pos;s<size;s++) {
1348 /* a segment costs us 8 bytes, so for more than 4 consecutive
1349 zero entries (16 bit each) in the glyph index array,
1350 it pays off to start a new segment */
1354 s -= count; // go to the last filled in entry
1359 void cmap_write(ttf_t* ttf, ttf_table_t*w)
1361 writeU16(w, 0); //version
1362 writeU16(w, 2); //two tables
1364 writeU16(w, 0); //platform (unicode)
1365 writeU16(w, 3); //encoding (unicode 2.0)
1366 writeU32(w, 20); //offset
1368 writeU16(w, 3); //platform (windows)
1369 writeU16(w, 1); //encoding (unicode basic multilingual plane UCS-2)
1370 writeU32(w, 20); //offset
1372 writeU16(w, 4); // format=4
1373 int length_pos = w->len;
1374 writeU16(w, 0); // length: we don't know yet
1375 writeU16(w, 0); // language (n/a for unicode)
1376 int num_segments_pos = w->len;
1377 writeU16(w, 0); //number of segments: we don't know yet either
1378 writeU16(w, 0); //searchrange
1379 writeU16(w, 0); //entry selector
1380 writeU16(w, 0); //range shift
1384 while(pos < ttf->unicode_size) {
1385 if(!ttf->unicode[pos]) {
1389 int s = segment_size(ttf->unicode, pos, ttf->unicode_size);
1394 num_segments++; // account for 0xffff mapping
1396 int glyphmap_start = w->len+2+num_segments*8;
1399 int end_pos = w->len;
1400 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
1401 writeU16(w, 0); //reserved byte
1402 int start_pos = w->len;
1403 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //start array
1404 int delta_pos = w->len;
1405 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //delta array
1406 int range_pos = w->len;
1407 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //range array
1409 /* backpatch number of segments */
1410 w->data[num_segments_pos++]=(num_segments*2)>>8;
1411 w->data[num_segments_pos++]=(num_segments*2);
1412 /* backpatch search range */
1413 int tmp = num_segments;
1414 int search_range = 0;
1419 w->data[num_segments_pos++]=(search_range*2)>>8;
1420 w->data[num_segments_pos++]=(search_range*2);
1421 /* backpatch entry selector */
1422 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;
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 U16 format = readU16(r);
1642 post->italic_angle = readU16(r);
1643 post->underline_position = readU16(r);
1644 post->underline_thickness = readU16(r);
1645 U16 is_monospaced = readU16(r);
1646 readU16(r); // min mem 42
1648 readU16(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 static int ttf_parse_tables(ttf_t*ttf)
1676 table = ttf_find_table(ttf, TAG_HEAD);
1678 msg("<error> Font has no head table");
1681 INIT_READ(m, table->data, table->len, 0);
1682 int loc_index = head_parse(ttf, &m);
1683 ttf_table_delete(ttf, table);
1685 table = ttf_find_table(ttf, TAG_MAXP);
1687 msg("<error> Font has no maxp table");
1690 INIT_READ(m2, table->data, table->len, 0);
1691 ttf->maxp = maxp_parse(ttf, &m2);
1692 ttf_table_delete(ttf, table);
1694 if(!ttf->num_glyphs) {
1695 msg("<error> Invalid number of characters");
1698 ttf->glyphs = rfx_calloc(sizeof(ttfglyph_t)*ttf->num_glyphs);
1700 table = ttf_find_table(ttf, TAG_OS2);
1702 INIT_READ(m, table->data, table->len, 0);
1703 ttf->os2 = os2_parse(&m);
1704 ttf_table_delete(ttf, table);
1708 table = ttf_find_table(ttf, TAG_HHEA);
1710 INIT_READ(m, table->data, table->len, 0);
1711 int num_advances = hea_parse(&m, ttf);
1712 ttf_table_delete(ttf, table);
1714 table = ttf_find_table(ttf, TAG_HMTX);
1716 INIT_READ(m, table->data, table->len, 0);
1717 mtx_parse(&m, ttf, num_advances);
1718 ttf_table_delete(ttf, table);
1721 table = ttf_find_table(ttf, TAG_VHEA);
1724 INIT_READ(m, table->data, table->len, 0);
1725 int num_advances = hea_parse(&m, ttf);
1726 ttf_table_delete(ttf, table);
1728 table = ttf_find_table(ttf, TAG_VMTX);
1730 INIT_READ(m, table->data, table->len, 0);
1731 mtx_parse(&m, ttf, num_advances);
1732 ttf_table_delete(ttf, table);
1735 msg("<error> Font contains neither HHEA nor VHEA");
1738 table = ttf_find_table(ttf, TAG_LOCA);
1740 INIT_READ(m, table->data, table->len, 0);
1741 U32*loca = loca_parse(&m, ttf, loc_index);
1742 ttf_table_delete(ttf, table);
1743 table = ttf_find_table(ttf, TAG_GLYF);
1745 INIT_READ(m, table->data, table->len, 0);
1746 glyf_parse(&m, ttf, loca);
1747 ttf_table_delete(ttf, table);
1752 table = ttf_find_table(ttf, TAG_CMAP);
1754 INIT_READ(m, table->data, table->len, 0);
1755 cmap_parse(&m, ttf);
1756 ttf_table_delete(ttf, table);
1759 table = ttf_find_table(ttf, TAG_POST);
1761 INIT_READ(m, table->data, table->len, 0);
1762 post_parse(&m, ttf);
1763 ttf_table_delete(ttf, table);
1766 table = ttf_find_table(ttf, TAG_NAME);
1768 INIT_READ(m, table->data, table->len, 0);
1769 name_parse(&m, ttf);
1770 ttf_table_delete(ttf, table);
1775 static void ttf_collapse_tables(ttf_t*ttf)
1779 ttf_table_t*head = ttf_find_table(ttf, TAG_HEAD);
1781 return; //already collapsed
1784 table = ttf_addtable(ttf, TAG_MAXP);
1785 maxp_write(ttf, table);
1790 table = ttf_addtable(ttf, TAG_OS2);
1791 os2_write(ttf, table);
1796 if(!ttf->is_vertical) {
1797 table = ttf_addtable(ttf, TAG_HMTX);
1798 int num_advances = mtx_write(ttf, table);
1799 table = ttf_addtable(ttf, TAG_HHEA);
1800 hea_write(ttf, table, num_advances);
1803 table = ttf_addtable(ttf, TAG_VMTX);
1804 int num_advances = mtx_write(ttf, table);
1805 table = ttf_addtable(ttf, TAG_VHEA);
1806 hea_write(ttf, table, num_advances);
1812 if(ttf->num_glyphs) {
1814 table = ttf_addtable(ttf, TAG_CMAP);
1815 cmap_write(ttf, table);
1820 table = ttf_addtable(ttf, TAG_GLYF);
1821 U32*locations = glyf_write(ttf, table);
1822 table = ttf_addtable(ttf, TAG_LOCA);
1823 loca_size = loca_write(ttf, table, locations);
1829 if(ttf->full_name || ttf->family_name || ttf->subfamily_name || ttf->font_uid || ttf->postscript_name) {
1830 table = ttf_addtable(ttf, TAG_NAME);
1831 name_write(ttf, table);
1835 table = ttf_addtable(ttf, TAG_POST);
1836 post_write(ttf, table);
1840 table = ttf_addtable(ttf, TAG_HEAD);
1841 head_write(ttf, table, loca_size);
1847 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1848 ttf->version = VERSION_1_0;
1851 ttf_t* ttf_load(void*data, int length)
1853 INIT_READ(r,data,length, 0);
1856 msg("<error> Truncated Truetype file (%d bytes)", length);
1860 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1861 ttf->version = readU32(&r);
1862 if(ttf->version == SWAP32(length)) {
1863 U32 fontDataSize = readU32(&r);
1864 U32 version = readU32(&r);
1865 U32 flags = readU32(&r);
1867 readBlock(&r, panose, 10);
1868 readU8(&r); //charset
1869 readU8(&r); //italoc
1870 readU32(&r); //weight
1871 readU16(&r); //fstype
1872 U16 magic = readU16(&r); //magicNumber
1873 /* we're being paranoid: it's entirely possible for the font
1874 size to be exactly 0x10000. Only treat this font as eot if
1875 it has the right magic number */
1876 if(magic == 0x4c50) {
1877 readU32(&r); //unicoderange[0]
1878 readU32(&r); //unicoderange[1]
1879 readU32(&r); //unicoderange[2]
1880 readU32(&r); //unicoderange[3]
1881 readU32(&r); //codepagerange[0]
1882 readU32(&r); //codepagerange[1]
1883 readU32(&r); //checksumadjustment
1884 readU32(&r); //reserved[0]
1885 readU32(&r); //reserved[1]
1886 readU32(&r); //reserved[2]
1887 readU32(&r); //reserved[3]
1888 readU16(&r); //padding
1891 for(nr=0;nr<4;nr++) {
1893 /* All of ttf is big-endian. All of ttf? No. One small eot table
1894 of indomitable little-endian... */
1896 len |= readU8(&r)<<8;
1898 for(t=0;t<len;t++) {
1899 U8 c = readU16(&r)>>8;
1901 readU16(&r); // zero terminator
1903 readU16(&r); // more padding
1905 /* adjust the offset to the start of the actual truetype
1906 data- the positions in the table header will be relative
1907 to the ttf data after the header, not to the file */
1911 ttf->version = readU32(&r);
1914 ttf->version = readU32(&r);
1918 if(ttf->version == TTCFTAG) {
1919 /* a ttc collection is a number of truetype fonts
1920 packaged together */
1922 msg("<error> Truncated TTC file (%d bytes)", length);
1925 U32 ttcf_version = readU32(&r); // 0x00000100: v1.0, 0x00000200: v2.0, includes DSIG table
1926 U32 num_fonts = readU32(&r); // number of fonts
1927 U32 font1_position = readU32(&r);
1928 if(font1_position+12 > length) {\
1929 msg("<error> Truncated TTC file (%d bytes, first font at %d)", length, font1_position);
1932 r.pos = font1_position;
1933 ttf->version = readU32(&r);
1936 int num_tables = readU16(&r);
1938 readU16(&r); //search range
1939 readU16(&r); //entry selector
1940 readU16(&r); //range shift
1942 if(num_tables*16 > length) {
1943 msg("<error> Truncated TTF file (table entries: %d)", num_tables);
1944 if(ttf->version != OPENTYPE &&
1945 ttf->version != TRUETYPE_MACOS &&
1946 ttf->version != VERSION_1_0) {
1947 // bad table length, weird version. This is probably not a ttf file.
1952 U32*table_data = malloc(16*num_tables);
1954 for(t=0;t<num_tables*4;t++) {
1955 table_data[t] = readU32(&r);
1957 for(t=0;t<num_tables;t++) {
1958 U32 tag = table_data[t*4];
1959 U32 checksum = table_data[t*4+1];
1960 U32 pos = table_data[t*4+2];
1961 U32 len = table_data[t*4+3];
1963 if(pos+len > length) {
1964 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);
1966 U8*mem = malloc(len);
1968 readBlock(&r, mem, len);
1970 ttf_table_t*table = ttf_addtable(ttf, tag);
1972 table->len = table->memsize = len;
1974 U32 checksum2 = ttf_table_checksum(table);
1975 if(checksum2!=checksum) {
1976 msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x",
1977 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1978 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1979 len, checksum2, checksum);
1986 if(!ttf_parse_tables(ttf))
1991 void ttf_create_truetype_tables(ttf_t*ttf)
1994 ttf->head = head_new(ttf);
1996 ttf->maxp = maxp_new(ttf);
1998 ttf->hea = hea_new(ttf);
2000 ttf->os2 = os2_new(ttf);
2002 ttf->post = post_new(ttf);
2005 ttf_table_t* ttf_write(ttf_t*ttf, U32*checksum_adjust)
2007 ttf_collapse_tables(ttf);
2009 ttf_table_t*file = ttf_table_new(0);
2010 writeU32(file, VERSION_1_0);
2012 /* write number of tables */
2014 ttf_table_t*t = ttf->tables;
2019 writeU16(file, num_tables);
2021 /* write search range */
2022 int tmp = num_tables;
2023 int search_range = 0;
2030 writeU16(file, search_range);
2032 /* write entry selector */
2033 int entry_selector = 0;
2038 writeU16(file, entry_selector);
2040 /* write range shift */
2041 int range_shift = num_tables*16 - search_range;
2042 writeU16(file, range_shift);
2044 /* write table dictionary */
2045 int table_dictionary_pos = file->len;
2046 int data_pos = file->len + num_tables*16;
2047 for(t=ttf->tables;t;t=t->next) {
2048 writeU32(file, t->id);
2049 writeU32(file, ttf_table_checksum(t));
2050 writeU32(file, data_pos);
2051 writeU32(file, t->len);
2053 data_pos += (-t->len)&3; //pad
2058 U8 zero[4]={0,0,0,0};
2059 for(t=ttf->tables;t;t=t->next) {
2060 if(t->id == TAG_HEAD)
2061 head_pos = file->len;
2062 writeBlock(file, t->data, t->len);
2063 writeBlock(file, zero, (-t->len)&3); //pad
2065 U32 checksum = 0xb1b0afba - ttf_table_checksum(file);
2067 *checksum_adjust = checksum;
2068 U8*checksum2 = file->data + head_pos + 8;
2069 checksum2[0] = checksum>>24;
2070 checksum2[1] = checksum>>16;
2071 checksum2[2] = checksum>>8;
2072 checksum2[3] = checksum>>0;
2076 ttf_table_t* ttf_eot_head(ttf_t*ttf)
2078 ttf_table_t*file = ttf_table_new(0);
2079 writeU32(file, 0); //file size (filled in later)
2080 writeU32(file, 0); //fontdatasize (filled in later)
2081 writeU32(file, 0x01000200);
2082 writeU32(file, 0); //flags
2083 writeU8(file, ttf->os2->panose_FamilyType);
2084 writeU8(file, ttf->os2->panose_SerifStyle);
2085 writeU8(file, ttf->os2->panose_Weight);
2086 writeU8(file, ttf->os2->panose_Proportion);
2087 writeU8(file, ttf->os2->panose_Contrast);
2088 writeU8(file, ttf->os2->panose_StrokeVariation);
2089 writeU8(file, ttf->os2->panose_ArmStyle);
2090 writeU8(file, ttf->os2->panose_Letterform);
2091 writeU8(file, ttf->os2->panose_Midline);
2092 writeU8(file, ttf->os2->panose_XHeight);
2093 writeU8(file, 1); //charset (default)
2094 writeU8(file, ttf->os2->fsSelection&1); //italic
2095 writeU32_LE(file, ttf->os2->usWeightClass);
2096 writeU16(file, 0); //fstype
2097 writeU16(file, 0x4c50); //magic
2098 writeU32_LE(file, ttf->os2->ulCharRange[0]);
2099 writeU32_LE(file, ttf->os2->ulCharRange[1]);
2100 writeU32_LE(file, ttf->os2->ulCharRange[2]);
2101 writeU32_LE(file, ttf->os2->ulCharRange[3]);
2102 writeU32_LE(file, ttf->os2->ulCodePageRange1);
2103 writeU32_LE(file, ttf->os2->ulCodePageRange2);
2104 writeU32(file, 0); //checksum adjust (filled in later)
2105 writeU32(file, 0); //reserved[0]
2106 writeU32(file, 0); //reserved[1]
2107 writeU32(file, 0); //reserved[2]
2108 writeU32(file, 0); //reserved[3]
2109 writeU16(file, 0); //padding(1)
2113 char* strings[] = {ttf->family_name, ttf->subfamily_name, ttf->version_string, ttf->full_name};
2114 int nr = sizeof(strings)/sizeof(strings[0]);
2117 char *string = strings[i];
2120 len = strlen(string);
2121 writeU16_LE(file, len*2);
2122 for(t=0;t<len;t++) {
2124 writeU8(file, string[t]);
2126 writeU16(file, 0); //zero byte pad
2129 writeU16(file, 0); //zero byte pad
2131 writeU16(file, 0); //padding(2)
2135 void ttf_save_eot(ttf_t*ttf, const char*filename)
2137 ttf_table_t* eot = ttf_eot_head(ttf);
2138 U32 checksum_adjust = 0;
2139 ttf_table_t* t = ttf_write(ttf, &checksum_adjust);
2141 U8*len_data = eot->data;
2142 U32 full_len = eot->len + t->len;
2143 len_data[0] = full_len>>0;
2144 len_data[1] = full_len>>8;
2145 len_data[2] = full_len>>16;
2146 len_data[3] = full_len>>24;
2148 U8*len_data2 = eot->data+4;
2149 len_data2[0] = t->len>>0;
2150 len_data2[1] = t->len>>8;
2151 len_data2[2] = t->len>>16;
2152 len_data2[3] = t->len>>24;
2154 U8*checksum_data = eot->data + 60;
2155 checksum_data[0] = checksum_adjust>>0;
2156 checksum_data[1] = checksum_adjust>>8;
2157 checksum_data[2] = checksum_adjust>>16;
2158 checksum_data[3] = checksum_adjust>>24;
2160 FILE*fi = fopen(filename, "wb");
2166 fwrite(eot->data, eot->len, 1, fi);
2167 fwrite(t->data, t->len, 1, fi);
2169 ttf_table_delete(0, t);
2170 ttf_table_delete(0, eot);
2173 void ttf_save(ttf_t*ttf, const char*filename)
2175 ttf_table_t* t = ttf_write(ttf, 0);
2176 FILE*fi = fopen(filename, "wb");
2181 fwrite(t->data, t->len, 1, fi);
2183 ttf_table_delete(0, t);
2186 void ttf_dump(ttf_t*ttf)
2188 msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
2189 ttf_table_t*table = ttf->tables;
2191 U32 tag = table->id;
2192 msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)",
2193 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
2194 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
2195 table = table->next;
2197 //ttf_table_dump(ttf_find_table(ttf, TAG_MAXP));
2205 void ttf_destroy_tables(ttf_t*ttf)
2207 ttf_table_t*table = ttf->tables;
2209 ttf_table_t*next = table->next;
2216 void ttf_reduce(ttf_t*ttf)
2218 ttf_destroy_tables(ttf);
2220 void ttf_destroy(ttf_t*ttf)
2222 ttf_destroy_tables(ttf);
2234 int main(int argn, const char*argv[])
2236 setConsoleLogging(7);
2237 const char*filename = "comic.ttf";
2240 //msg("<notice> Loading %s", filename);
2241 memfile_t*m = memfile_open(filename);
2242 ttf_t*ttf = ttf_load(m->data, m->len);
2245 msg("<error> Couldn't load %s", filename);
2250 ttf->full_name = strdup("Test-Normal");
2251 ttf->family_name = strdup("Test");
2252 ttf->subfamily_name = strdup("Normal");
2253 ttf->version_string = strdup("Version 1.0");
2254 ttf->font_uid = strdup("omguid");
2255 ttf->postscript_name = strdup("Test-psname");
2260 //printf("os2 version: %04x (%d), maxp size: %d\n",
2261 // ttf->os2->version, ttf->os2->size, ttf->maxp->size);
2262 ttf_save_eot(ttf, "testfont.eot");
2263 ttf_save(ttf, "testfont.ttf");