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;
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 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 if(ttf->family_name) free(ttf->family_name);
1523 ttf->family_name = readString(&s, len);
1526 if(ttf->subfamily_name) free(ttf->subfamily_name);
1527 ttf->subfamily_name = readString(&s, len);
1530 if(ttf->version_string) free(ttf->version_string);
1531 ttf->version_string = readString(&s, len);
1534 if(ttf->full_name) free(ttf->full_name);
1535 ttf->full_name = readString(&s, len);
1539 void name_write(ttf_t*ttf, ttf_table_t*table)
1541 char*strings[4] = {ttf->family_name, ttf->subfamily_name, ttf->version_string, ttf->full_name};
1542 int codes[4] = {1,2,3,4};
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;
1625 static table_post_t*post_new(ttf_t*ttf)
1627 table_post_t*post = rfx_calloc(sizeof(table_post_t));
1630 void post_parse(memreader_t*r, ttf_t*ttf)
1632 table_post_t*post = ttf->post = rfx_calloc(sizeof(table_post_t));
1633 U16 format = readU16(r);
1634 post->italic_angle = readU16(r);
1635 post->underline_position = readU16(r);
1636 post->underline_thickness = readU16(r);
1637 U16 is_monospaced = readU16(r);
1638 readU16(r); // min mem 42
1640 readU16(r); // min mem 1
1643 void post_write(ttf_t*ttf, ttf_table_t*table)
1645 table_post_t*post = ttf->post;
1646 writeU32(table, 0x00030000);
1647 writeU32(table, post->italic_angle);
1648 writeU16(table, post->underline_position);
1649 writeU16(table, post->underline_thickness);
1650 writeU32(table, 0); //is monospaced TODO
1651 writeU32(table, 0); //min mem 42
1653 writeU32(table, 0); //min mem 1
1656 void post_delete(ttf_t*ttf)
1664 static int ttf_parse_tables(ttf_t*ttf)
1668 table = ttf_find_table(ttf, TAG_HEAD);
1670 msg("<error> Font has no head table");
1673 INIT_READ(m, table->data, table->len, 0);
1674 int loc_index = head_parse(ttf, &m);
1675 ttf_table_delete(ttf, table);
1677 table = ttf_find_table(ttf, TAG_MAXP);
1679 msg("<error> Font has no maxp table");
1682 INIT_READ(m2, table->data, table->len, 0);
1683 ttf->maxp = maxp_parse(ttf, &m2);
1684 ttf_table_delete(ttf, table);
1686 if(!ttf->num_glyphs) {
1687 msg("<error> Invalid number of characters");
1690 ttf->glyphs = rfx_calloc(sizeof(ttfglyph_t)*ttf->num_glyphs);
1692 table = ttf_find_table(ttf, TAG_OS2);
1694 INIT_READ(m, table->data, table->len, 0);
1695 ttf->os2 = os2_parse(&m);
1696 ttf_table_delete(ttf, table);
1700 table = ttf_find_table(ttf, TAG_HHEA);
1702 INIT_READ(m, table->data, table->len, 0);
1703 int num_advances = hea_parse(&m, ttf);
1704 ttf_table_delete(ttf, table);
1706 table = ttf_find_table(ttf, TAG_HMTX);
1708 INIT_READ(m, table->data, table->len, 0);
1709 mtx_parse(&m, ttf, num_advances);
1710 ttf_table_delete(ttf, table);
1713 table = ttf_find_table(ttf, TAG_VHEA);
1716 INIT_READ(m, table->data, table->len, 0);
1717 int num_advances = hea_parse(&m, ttf);
1718 ttf_table_delete(ttf, table);
1720 table = ttf_find_table(ttf, TAG_VMTX);
1722 INIT_READ(m, table->data, table->len, 0);
1723 mtx_parse(&m, ttf, num_advances);
1724 ttf_table_delete(ttf, table);
1727 msg("<error> Font contains neither HHEA nor VHEA");
1730 table = ttf_find_table(ttf, TAG_LOCA);
1732 INIT_READ(m, table->data, table->len, 0);
1733 U32*loca = loca_parse(&m, ttf, loc_index);
1734 ttf_table_delete(ttf, table);
1735 table = ttf_find_table(ttf, TAG_GLYF);
1737 INIT_READ(m, table->data, table->len, 0);
1738 glyf_parse(&m, ttf, loca);
1739 ttf_table_delete(ttf, table);
1744 table = ttf_find_table(ttf, TAG_CMAP);
1746 INIT_READ(m, table->data, table->len, 0);
1747 cmap_parse(&m, ttf);
1748 ttf_table_delete(ttf, table);
1751 table = ttf_find_table(ttf, TAG_POST);
1753 INIT_READ(m, table->data, table->len, 0);
1754 post_parse(&m, ttf);
1755 ttf_table_delete(ttf, table);
1758 table = ttf_find_table(ttf, TAG_NAME);
1760 INIT_READ(m, table->data, table->len, 0);
1761 name_parse(&m, ttf);
1762 ttf_table_delete(ttf, table);
1767 static void ttf_collapse_tables(ttf_t*ttf)
1771 ttf_table_t*head = ttf_find_table(ttf, TAG_HEAD);
1773 return; //already collapsed
1776 table = ttf_addtable(ttf, TAG_MAXP);
1777 maxp_write(ttf, table);
1782 table = ttf_addtable(ttf, TAG_OS2);
1783 os2_write(ttf, table);
1788 if(!ttf->is_vertical) {
1789 table = ttf_addtable(ttf, TAG_HMTX);
1790 int num_advances = mtx_write(ttf, table);
1791 table = ttf_addtable(ttf, TAG_HHEA);
1792 hea_write(ttf, table, num_advances);
1795 table = ttf_addtable(ttf, TAG_VMTX);
1796 int num_advances = mtx_write(ttf, table);
1797 table = ttf_addtable(ttf, TAG_VHEA);
1798 hea_write(ttf, table, num_advances);
1804 if(ttf->num_glyphs) {
1806 table = ttf_addtable(ttf, TAG_CMAP);
1807 cmap_write(ttf, table);
1812 table = ttf_addtable(ttf, TAG_GLYF);
1813 U32*locations = glyf_write(ttf, table);
1814 table = ttf_addtable(ttf, TAG_LOCA);
1815 loca_size = loca_write(ttf, table, locations);
1821 if(ttf->full_name || ttf->family_name || ttf->subfamily_name) {
1822 table = ttf_addtable(ttf, TAG_NAME);
1823 name_write(ttf, table);
1827 table = ttf_addtable(ttf, TAG_POST);
1828 post_write(ttf, table);
1832 table = ttf_addtable(ttf, TAG_HEAD);
1833 head_write(ttf, table, loca_size);
1839 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1840 ttf->version = VERSION_1_0;
1843 ttf_t* ttf_load(void*data, int length)
1845 INIT_READ(r,data,length, 0);
1848 msg("<error> Truncated Truetype file (%d bytes)", length);
1852 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1853 ttf->version = readU32(&r);
1854 if(ttf->version == SWAP32(length)) {
1855 U32 fontDataSize = readU32(&r);
1856 U32 version = readU32(&r);
1857 U32 flags = readU32(&r);
1859 readBlock(&r, panose, 10);
1860 readU8(&r); //charset
1861 readU8(&r); //italoc
1862 readU32(&r); //weight
1863 readU16(&r); //fstype
1864 U16 magic = readU16(&r); //magicNumber
1865 /* we're being paranoid: it's entirely possible for the font
1866 size to be exactly 0x10000. Only treat this font as eot if
1867 it has the right magic number */
1868 if(magic == 0x4c50) {
1869 readU32(&r); //unicoderange[0]
1870 readU32(&r); //unicoderange[1]
1871 readU32(&r); //unicoderange[2]
1872 readU32(&r); //unicoderange[3]
1873 readU32(&r); //codepagerange[0]
1874 readU32(&r); //codepagerange[1]
1875 readU32(&r); //checksumadjustment
1876 readU32(&r); //reserved[0]
1877 readU32(&r); //reserved[1]
1878 readU32(&r); //reserved[2]
1879 readU32(&r); //reserved[3]
1880 readU16(&r); //padding
1883 for(nr=0;nr<4;nr++) {
1885 /* All of ttf is big-endian. All of ttf? No. One small eot table
1886 of indomitable little-endian... */
1888 len |= readU8(&r)<<8;
1890 for(t=0;t<len;t++) {
1891 U8 c = readU16(&r)>>8;
1893 readU16(&r); // zero terminator
1895 readU16(&r); // more padding
1897 /* adjust the offset to the start of the actual truetype
1898 data- the positions in the table header will be relative
1899 to the ttf data after the header, not to the file */
1903 ttf->version = readU32(&r);
1906 ttf->version = readU32(&r);
1910 if(ttf->version == TTCFTAG) {
1911 /* a ttc collection is a number of truetype fonts
1912 packaged together */
1914 msg("<error> Truncated TTC file (%d bytes)", length);
1917 U32 ttcf_version = readU32(&r); // 0x00000100: v1.0, 0x00000200: v2.0, includes DSIG table
1918 U32 num_fonts = readU32(&r); // number of fonts
1919 U32 font1_position = readU32(&r);
1920 if(font1_position+12 > length) {\
1921 msg("<error> Truncated TTC file (%d bytes, first font at %d)", length, font1_position);
1924 r.pos = font1_position;
1925 ttf->version = readU32(&r);
1928 int num_tables = readU16(&r);
1930 readU16(&r); //search range
1931 readU16(&r); //entry selector
1932 readU16(&r); //range shift
1934 if(num_tables*16 > length) {
1935 msg("<error> Truncated TTF file (table entries: %d)", num_tables);
1936 if(ttf->version != OPENTYPE &&
1937 ttf->version != TRUETYPE_MACOS &&
1938 ttf->version != VERSION_1_0) {
1939 // bad table length, weird version. This is probably not a ttf file.
1944 U32*table_data = malloc(16*num_tables);
1946 for(t=0;t<num_tables*4;t++) {
1947 table_data[t] = readU32(&r);
1949 for(t=0;t<num_tables;t++) {
1950 U32 tag = table_data[t*4];
1951 U32 checksum = table_data[t*4+1];
1952 U32 pos = table_data[t*4+2];
1953 U32 len = table_data[t*4+3];
1955 if(pos+len > length) {
1956 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);
1958 U8*mem = malloc(len);
1960 readBlock(&r, mem, len);
1962 ttf_table_t*table = ttf_addtable(ttf, tag);
1964 table->len = table->memsize = len;
1966 U32 checksum2 = ttf_table_checksum(table);
1967 if(checksum2!=checksum) {
1968 msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x",
1969 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1970 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1971 len, checksum2, checksum);
1978 if(!ttf_parse_tables(ttf))
1983 void ttf_create_truetype_tables(ttf_t*ttf)
1986 ttf->head = head_new(ttf);
1988 ttf->maxp = maxp_new(ttf);
1990 ttf->hea = hea_new(ttf);
1992 ttf->os2 = os2_new(ttf);
1994 ttf->post = post_new(ttf);
1997 ttf_table_t* ttf_write(ttf_t*ttf, U32*checksum_adjust)
1999 ttf_collapse_tables(ttf);
2001 ttf_table_t*file = ttf_table_new(0);
2002 writeU32(file, VERSION_1_0);
2004 /* write number of tables */
2006 ttf_table_t*t = ttf->tables;
2011 writeU16(file, num_tables);
2013 /* write search range */
2014 int tmp = num_tables;
2015 int search_range = 0;
2022 writeU16(file, search_range);
2024 /* write entry selector */
2025 int entry_selector = 0;
2030 writeU16(file, entry_selector);
2032 /* write range shift */
2033 int range_shift = num_tables*16 - search_range;
2034 writeU16(file, range_shift);
2036 /* write table dictionary */
2037 int table_dictionary_pos = file->len;
2038 int data_pos = file->len + num_tables*16;
2039 for(t=ttf->tables;t;t=t->next) {
2040 writeU32(file, t->id);
2041 writeU32(file, ttf_table_checksum(t));
2042 writeU32(file, data_pos);
2043 writeU32(file, t->len);
2045 data_pos += (-t->len)&3; //pad
2050 U8 zero[4]={0,0,0,0};
2051 for(t=ttf->tables;t;t=t->next) {
2052 if(t->id == TAG_HEAD)
2053 head_pos = file->len;
2054 writeBlock(file, t->data, t->len);
2055 writeBlock(file, zero, (-t->len)&3); //pad
2057 U32 checksum = 0xb1b0afba - ttf_table_checksum(file);
2059 *checksum_adjust = checksum;
2060 U8*checksum2 = file->data + head_pos + 8;
2061 checksum2[0] = checksum>>24;
2062 checksum2[1] = checksum>>16;
2063 checksum2[2] = checksum>>8;
2064 checksum2[3] = checksum>>0;
2068 ttf_table_t* ttf_eot_head(ttf_t*ttf)
2070 ttf_table_t*file = ttf_table_new(0);
2071 writeU32(file, 0); //file size (filled in later)
2072 writeU32(file, 0); //fontdatasize (filled in later)
2073 writeU32(file, 0x01000200);
2074 writeU32(file, 0); //flags
2075 writeU8(file, ttf->os2->panose_FamilyType);
2076 writeU8(file, ttf->os2->panose_SerifStyle);
2077 writeU8(file, ttf->os2->panose_Weight);
2078 writeU8(file, ttf->os2->panose_Proportion);
2079 writeU8(file, ttf->os2->panose_Contrast);
2080 writeU8(file, ttf->os2->panose_StrokeVariation);
2081 writeU8(file, ttf->os2->panose_ArmStyle);
2082 writeU8(file, ttf->os2->panose_Letterform);
2083 writeU8(file, ttf->os2->panose_Midline);
2084 writeU8(file, ttf->os2->panose_XHeight);
2085 writeU8(file, 1); //charset (default)
2086 writeU8(file, ttf->os2->fsSelection&1); //italic
2087 writeU32_LE(file, ttf->os2->usWeightClass);
2088 writeU16(file, 0); //fstype
2089 writeU16(file, 0x4c50); //magic
2090 writeU32_LE(file, ttf->os2->ulCharRange[0]);
2091 writeU32_LE(file, ttf->os2->ulCharRange[1]);
2092 writeU32_LE(file, ttf->os2->ulCharRange[2]);
2093 writeU32_LE(file, ttf->os2->ulCharRange[3]);
2094 writeU32_LE(file, ttf->os2->ulCodePageRange1);
2095 writeU32_LE(file, ttf->os2->ulCodePageRange2);
2096 writeU32(file, 0); //checksum adjust (filled in later)
2097 writeU32(file, 0); //reserved[0]
2098 writeU32(file, 0); //reserved[1]
2099 writeU32(file, 0); //reserved[2]
2100 writeU32(file, 0); //reserved[3]
2101 writeU16(file, 0); //padding(1)
2106 len = strlen(ttf->family_name);
2107 writeU16_LE(file, len*2);
2108 for(t=0;t<len;t++) {
2110 writeU8(file, ttf->family_name[t]);
2112 writeU16(file, 0); //zero byte pad
2115 len = strlen(ttf->subfamily_name);
2116 writeU16_LE(file, len*2);
2117 for(t=0;t<len;t++) {
2119 writeU8(file, ttf->subfamily_name[t]);
2121 writeU16(file, 0); //zero byte pad
2124 len = strlen(ttf->version_string);
2125 writeU16_LE(file, len*2); //len
2126 for(t=0;t<len;t++) {
2128 writeU8(file, ttf->version_string[t]);
2130 writeU16(file, 0); //zero byte pad
2133 len = strlen(ttf->full_name);
2134 writeU16_LE(file, len*2); //len
2135 for(t=0;t<len;t++) {
2137 writeU8(file, ttf->full_name[t]);
2139 writeU16(file, 0); //zero byte pad
2141 writeU16(file, 0); //padding(2)
2145 void ttf_save_eot(ttf_t*ttf, const char*filename)
2147 ttf_table_t* eot = ttf_eot_head(ttf);
2148 U32 checksum_adjust = 0;
2149 ttf_table_t* t = ttf_write(ttf, &checksum_adjust);
2151 U8*len_data = eot->data;
2152 U32 full_len = eot->len + t->len;
2153 len_data[0] = full_len>>0;
2154 len_data[1] = full_len>>8;
2155 len_data[2] = full_len>>16;
2156 len_data[3] = full_len>>24;
2158 U8*len_data2 = eot->data+4;
2159 len_data2[0] = t->len>>0;
2160 len_data2[1] = t->len>>8;
2161 len_data2[2] = t->len>>16;
2162 len_data2[3] = t->len>>24;
2164 U8*checksum_data = eot->data + 60;
2165 checksum_data[0] = checksum_adjust>>0;
2166 checksum_data[1] = checksum_adjust>>8;
2167 checksum_data[2] = checksum_adjust>>16;
2168 checksum_data[3] = checksum_adjust>>24;
2170 FILE*fi = fopen(filename, "wb");
2176 fwrite(eot->data, eot->len, 1, fi);
2177 fwrite(t->data, t->len, 1, fi);
2179 ttf_table_delete(0, t);
2180 ttf_table_delete(0, eot);
2183 void ttf_save(ttf_t*ttf, const char*filename)
2185 ttf_table_t* t = ttf_write(ttf, 0);
2186 FILE*fi = fopen(filename, "wb");
2191 fwrite(t->data, t->len, 1, fi);
2193 ttf_table_delete(0, t);
2196 void ttf_dump(ttf_t*ttf)
2198 msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
2199 ttf_table_t*table = ttf->tables;
2201 U32 tag = table->id;
2202 msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)",
2203 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
2204 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
2205 table = table->next;
2207 //ttf_table_dump(ttf_find_table(ttf, TAG_MAXP));
2215 void ttf_destroy_tables(ttf_t*ttf)
2217 ttf_table_t*table = ttf->tables;
2219 ttf_table_t*next = table->next;
2226 void ttf_reduce(ttf_t*ttf)
2228 ttf_destroy_tables(ttf);
2230 void ttf_destroy(ttf_t*ttf)
2232 ttf_destroy_tables(ttf);
2244 int main(int argn, const char*argv[])
2246 setConsoleLogging(7);
2247 const char*filename = "comic.ttf";
2250 //msg("<notice> Loading %s", filename);
2251 memfile_t*m = memfile_open(filename);
2252 ttf_t*ttf = ttf_load(m->data, m->len);
2255 msg("<error> Couldn't load %s", filename);
2260 ttf->full_name = strdup("Test-Normal");
2261 ttf->family_name = strdup("Test");
2262 ttf->subfamily_name = strdup("Normal");
2263 ttf->version_string = strdup("Version 1.0");
2268 //printf("os2 version: %04x (%d), maxp size: %d\n",
2269 // ttf->os2->version, ttf->os2->size, ttf->maxp->size);
2270 ttf_save_eot(ttf, "testfont.eot");
2271 ttf_save(ttf, "testfont.ttf");