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 */
30 #define TTCFTAG 0x74746366
32 #define OPENTYPE 0x4f54544f
33 #define TRUETYPE_MACOS 0x74727565
34 #define VERSION_1_0 0x00010000
36 #define TAG_OS2 0x4f532f32
37 #define TAG_CMAP 0x636d6170
38 #define TAG_GLYF 0x676c7966 //required for non opentype
39 #define TAG_HEAD 0x68656164 //required
40 #define TAG_HHEA 0x68686561 //required
41 #define TAG_HMTX 0x686d7478 //required
42 #define TAG_VHEA 0x86686561
43 #define TAG_VMTX 0x866d7478
44 #define TAG_KERN 0x6b65726e
45 #define TAG_LOCA 0x6c6f6361 //required for non opentype
46 #define TAG_MAXP 0x6d617870 //required
47 #define TAG_NAME 0x6e616d65
48 #define TAG_POST 0x706f7374
49 #define TAG_CFF 0x43464620 //required for opentype
52 fpgm - assembly instructions
53 prep - assembly instructions
54 cvt - constant value table
55 gasp - gridfitting procedure
58 static U32 checksum_block(U8*_data, int len)
64 int len_minus_4 = len-4;
65 for(pos=0;pos<=len_minus_4;pos+=4) {
66 sum += data[pos]<<24|data[pos+1]<<16|data[pos+2]<<8|data[pos+3];
69 if(left == 1) sum+= data[pos+0]<<24;
70 if(left == 2) sum+= data[pos+0]<<24|data[pos+1]<<16;
71 if(left == 3) sum+= data[pos+0]<<24|data[pos+1]<<16|data[pos+2]<<8;
75 typedef struct _memreader {
81 static U8 readU8(memreader_t*r)
83 return r->mem[r->pos++];
85 static inline U16 readU16(memreader_t*r)
87 if(r->pos+2>r->size) return 0;
88 U16 val = r->mem[r->pos]<<8|
93 static S16 readS16(memreader_t*r)
95 return (S16)readU16(r);
97 static U32 readU32(memreader_t*r)
99 if(r->pos+4>r->size) return 0;
100 U32 val = r->mem[r->pos]<<24|
101 r->mem[r->pos+1]<<16|
107 static void readBlock(memreader_t*r, void*dest, int len)
109 int remaining = r->size-r->pos;
110 if(len > remaining) {
111 memcpy(dest, r->mem+r->pos, remaining);
112 memset(dest+remaining, 0, len - remaining);
115 memcpy(dest, r->mem+r->pos, len);
119 #define INIT_READ(r,data,length,pos) memreader_t r = {(data),(pos),(length)};
121 static void expand(ttf_table_t*w, int newsize)
123 int v1 = (newsize+63)&~63;
124 int v2 = w->len + w->len / 2;
125 w->memsize = v1>v2?v1:v2;
126 w->data = rfx_realloc(w->data, w->memsize);
128 static inline void writeU8(ttf_table_t*w, unsigned char b)
130 if(w->memsize<w->len+1)
132 w->data[w->len++] = b;
134 static inline void writeU16(ttf_table_t*w, unsigned short v)
136 if(w->memsize<w->len+2)
138 w->data[w->len++] = v>>8;
139 w->data[w->len++] = v;
141 #define writeS16 writeU16
142 static inline void writeU32(ttf_table_t*w, unsigned long v)
144 if(w->memsize<w->len+4)
146 w->data[w->len++] = v>>24;
147 w->data[w->len++] = v>>16;
148 w->data[w->len++] = v>>8;
149 w->data[w->len++] = v;
151 static inline void writeBlock(ttf_table_t*w, void*data, int len)
153 if(w->memsize<w->len+len)
154 expand(w, w->len+len);
155 memcpy(w->data+w->len, data, len);
159 ttf_table_t*ttf_table_new(U32 id)
161 ttf_table_t*t = rfx_calloc(sizeof(ttf_table_t));
166 ttf_table_t*ttf_addtable(ttf_t*ttf, U32 id)
168 ttf_table_t*t = ttf_table_new(id);
170 ttf_table_t*before,*after=0;
171 for(before=ttf->tables; before&&before->id<id; before=before->next) {
174 if(before && before->id == id) {
175 msg("<error> Error: duplicate table %08x", id);
183 t->next = ttf->tables;
187 t->next = after->next;
194 ttf_table_t*ttf_find_table(ttf_t*ttf, U32 id)
196 ttf_table_t*table = ttf->tables;
204 void ttf_table_delete(ttf_t*ttf, ttf_table_t*table)
206 if(ttf && ttf->tables == table) {
207 ttf->tables = table->next;
210 table->prev->next = table->next;
212 table->next->prev = table->prev;
216 U32 ttf_table_checksum(ttf_table_t*t)
218 U32 checksum = checksum_block(t->data, t->len);
219 if(t->id==TAG_HEAD && t->len>=12) {
220 /* the checksum for the HEAD table is calculated by masking out
221 the checksumadjust field */
222 U32 adjust = t->data[8]<<24|t->data[9]<<16|t->data[10]<<8|t->data[11];
227 static U8 printable(U8 a)
229 if(a<32 || a==127) return '.';
232 static void hexdump(U8*data, int len, const char*prefix)
236 printf("%s -=> ",prefix);
238 printf("%02x ", data[t]);
239 ascii[t&15] = printable(data[t]);
240 if((t && ((t&15)==15)) || (t==len-1))
244 for(s=p-1;s<16;s++) {
248 printf(" %s\n", ascii);
250 printf(" %s\n%s -=> ",ascii,prefix);
254 static void ttf_table_dump(ttf_table_t*t, const char*prefix)
257 hexdump(t->data, t->len, prefix);
260 static table_head_t*head_new(ttf_t*ttf)
262 table_head_t*head = rfx_calloc(sizeof(table_head_t));
263 head->units_per_em = 1024;
265 if(ttf->num_glyphs) {
266 head->xmin = ttf->glyphs[0].xmin;
267 head->ymin = ttf->glyphs[0].ymin;
268 head->xmax = ttf->glyphs[0].xmax;
269 head->ymax = ttf->glyphs[0].ymax;
270 for(t=1;t<ttf->num_glyphs;t++) {
271 if(ttf->glyphs[t].xmin < head->xmin) head->xmin = ttf->glyphs[t].xmin;
272 if(ttf->glyphs[t].ymin < head->ymin) head->ymin = ttf->glyphs[t].ymin;
273 if(ttf->glyphs[t].xmax > head->xmax) head->xmax = ttf->glyphs[t].xmax;
274 if(ttf->glyphs[t].ymax > head->ymax) head->ymax = ttf->glyphs[t].ymax;
278 head->lowest_readable_size = 8; // not sure what font renderers actually do with this
282 static int head_parse(ttf_t*ttf, memreader_t*r)
284 ttf->head = rfx_calloc(sizeof(table_head_t));
285 U32 version = readU32(r);
286 if(version!=VERSION_1_0)
287 msg("<warning> Font HEAD has unknown version %08x", version);
288 U32 revision = readU32(r);
289 U32 checksum2 = readU32(r);
290 U32 magic = readU32(r);
291 if(magic!=0x5f0f3cf5)
292 msg("<warning> Font HEAD has unknown magic number %08x", magic);
293 ttf->head->flags = readU16(r);
294 ttf->head->units_per_em = readU16(r);
295 readU32(r);readU32(r); //created
296 readU32(r);readU32(r); //modified
297 ttf->head->xmin = readU16(r);
298 ttf->head->ymin = readU16(r);
299 ttf->head->xmax = readU16(r);
300 ttf->head->ymax = readU16(r);
301 ttf->head->macStyle = readU16(r);
302 ttf->head->lowest_readable_size = readU16(r); //in pixels
303 ttf->head->dir_hint = readS16(r);
304 int loc_index = readS16(r); //used in 'loca' table
306 msg("<warning> loca index format %d unknown", loc_index);
307 U16 glyph_data_format = readS16(r);
308 if(glyph_data_format!=0)
309 msg("<warning> Font glyph data format unknown: %04x", glyph_data_format);
310 if(r->pos < r->size) {
311 msg("<warning> Leftover bytes (%d) in HEAD tag", r->size - r->pos);
315 static void head_write(ttf_t*ttf, ttf_table_t*w, int loca_size)
317 writeU32(w, 0x10000);
318 writeU32(w, 0x10000);
319 writeU32(w, 0); //checksum
320 writeU32(w, 0x5f0f3cf5); //magic
321 writeU16(w, ttf->head->flags);
322 writeU16(w, ttf->head->units_per_em);
323 writeU32(w, 0);writeU32(w, 0); //created
324 writeU32(w, 0);writeU32(w, 0); //modified
325 writeU16(w, ttf->head->xmin);
326 writeU16(w, ttf->head->ymin);
327 writeU16(w, ttf->head->xmax);
328 writeU16(w, ttf->head->ymax);
329 writeU16(w, ttf->head->macStyle);
330 writeU16(w, ttf->head->lowest_readable_size);
331 writeS16(w, ttf->head->dir_hint);
332 writeS16(w, loca_size); //loca index size (32 bit)
333 writeS16(w, 0); //glyph data format
335 static void head_dump(ttf_t*ttf)
337 printf("head->flags: %d\n", ttf->head->flags);
338 printf("head->units_per_em: %d\n", ttf->head->units_per_em);
339 printf("head->xmin: %d\n", ttf->head->xmin);
340 printf("head->ymin: %d\n", ttf->head->ymin);
341 printf("head->xmax: %d\n", ttf->head->xmax);
342 printf("head->ymax: %d\n", ttf->head->ymax);
343 printf("head->macStyle: %d\n", ttf->head->macStyle);
344 printf("head->lowest_readable_size: %d\n", ttf->head->lowest_readable_size);
345 printf("head->dir_hint: %d\n", ttf->head->dir_hint);
347 static void head_delete(ttf_t*ttf)
355 static table_os2_t*os2_new(ttf_t*ttf)
357 table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
358 if(ttf->num_glyphs) {
361 for(t=0;t<ttf->num_glyphs;t++) {
362 average_width += (ttf->glyphs[t].advance + ttf->glyphs[t].bearing);
364 os2->xAvgCharWidth = average_width / ttf->num_glyphs;
367 /* that's what everybody seems to fill in */
368 os2->usWeightClass = 400;
369 os2->usWidthClass = 5;
372 int advance = (ttf->head->xmax - ttf->head->xmin)/2;
373 int height = (ttf->head->xmax - ttf->head->xmin);
375 /* I do believe a sane font rendering engine will actually use
376 the font advance here- the subscript/superscript position will
377 not be the same for each glyph */
378 os2->ySuperscriptXSize = os2->ySubscriptXSize = (ttf->head->xmax - ttf->head->xmin)/2;
379 os2->ySuperscriptYSize = os2->ySubscriptYSize = (ttf->head->ymax - ttf->head->ymin)/2;
380 os2->ySubscriptXOffset = advance;
381 os2->ySubscriptYOffset = 0;
382 os2->ySuperscriptXOffset = advance;
383 os2->ySuperscriptYOffset = (ttf->head->ymax - ttf->head->ymin)/2;
384 os2->yStrikeoutSize = ttf->head->units_per_em / 10;
385 os2->yStrikeoutPosition = ymid;
386 os2->usWinAscent = ttf->head->ymax;
387 os2->usWinDescent = ttf->head->ymin<0?0:ttf->head->ymin;
388 os2->sxHeight = ymid;
389 os2->sCapHeight = height*2/3;
391 os2->panose_Weight = 4;
393 /* strictly speaking we'd have to set 92/64 bits in these tables, depending on
394 what parts of the unicode table is filled. (e.g. bit 90 = tibetan). */
395 os2->ulCharRange[0] = 1;
396 os2->ulCharRange[1] = 0;
397 os2->ulCharRange[2] = 0;
398 os2->ulCharRange[3] = 0;
399 os2->ulCodePageRange1 = 1;
400 os2->ulCodePageRange2 = 0;
402 if(ttf->unicode_size) {
404 for(min=0;min<ttf->unicode_size;min++)
405 if(ttf->unicode[min]) break;
406 for(max=ttf->unicode_size-1;max>=0;max--)
407 if(ttf->unicode[max]) break;
409 os2->fsFirstCharIndex = min;
410 os2->fsLastCharIndex = max;
413 os2->sTypoAscender = ttf->ascent;
414 os2->sTypoDescender = ttf->descent;
415 os2->sTypoLineGap = ttf->lineGap;
417 os2->usDefaultChar = 0;
418 os2->usBreakChar = (ttf->unicode_size>0x20 && ttf->unicode[0x20])?0x20:0;
419 os2->usMaxContext = 0; // we don't use ligatures yet
422 static table_os2_t*os2_parse(memreader_t*r)
424 table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
425 U16 version = readU16(r);
430 if(version!=0 && version!=1 && version!=2 && version!=3)
431 msg("<warning> Unknown OS2 version: %04x", version);
432 os2->xAvgCharWidth = readS16(r);
433 os2->usWeightClass = readU16(r);
434 os2->usWidthClass = readU16(r);
436 os2->ySubscriptXSize = readU16(r);
437 os2->ySubscriptYSize = readU16(r);
438 os2->ySubscriptXOffset = readU16(r);
439 os2->ySubscriptYOffset = readU16(r);
440 os2->ySuperscriptXSize = readU16(r);
441 os2->ySuperscriptYSize = readU16(r);
442 os2->ySuperscriptXOffset = readU16(r);
443 os2->ySuperscriptYOffset = readU16(r);
444 os2->yStrikeoutSize = readU16(r);
445 os2->yStrikeoutPosition = readU16(r);
446 os2->sFamilyClass = readU16(r);
447 os2->panose_FamilyType = readU8(r);
448 os2->panose_SerifStyle = readU8(r);
449 os2->panose_Weight = readU8(r);
450 os2->panose_Proportion = readU8(r);
451 os2->panose_Contrast = readU8(r);
452 os2->panose_StrokeVariation = readU8(r);
453 os2->panose_ArmStyle = readU8(r);
454 os2->panose_Letterform = readU8(r);
455 os2->panose_Midline = readU8(r);
456 os2->panose_XHeight = readU8(r);
457 os2->ulCharRange[0] = readU32(r);
458 os2->ulCharRange[1] = readU32(r);
459 os2->ulCharRange[2] = readU32(r);
460 os2->ulCharRange[3] = readU32(r);
462 os2->fsSelection = readU16(r);
463 os2->fsFirstCharIndex = readU16(r);
464 os2->fsLastCharIndex = readU16(r);
465 os2->sTypoAscender = readS16(r);
466 os2->sTypoDescender = readS16(r);
467 os2->sTypoLineGap = readS16(r);
468 os2->usWinAscent = readU16(r);
469 os2->usWinDescent = readU16(r);
470 if(version<1) return os2;
471 os2->ulCodePageRange1 = readU32(r);
472 os2->ulCodePageRange2 = readU32(r);
473 if(version<2) return os2;
474 os2->sxHeight = readS16(r);
475 os2->sCapHeight = readS16(r);
476 os2->usDefaultChar = readU16(r);
477 os2->usBreakChar = readU16(r);
478 os2->usMaxContext = readU16(r);
480 if(r->pos < r->size) {
481 msg("<warning> Leftover bytes (%d) in OS2 tag", r->size - r->pos);
485 static void os2_write(ttf_t*ttf, ttf_table_t*w)
487 table_os2_t*os2 = ttf->os2;
489 if(os2->sxHeight|os2->sCapHeight|os2->usDefaultChar|os2->usBreakChar|os2->usMaxContext) {
492 writeU16(w, version);
493 writeS16(w, os2->xAvgCharWidth);
494 writeU16(w, os2->usWeightClass);
495 writeU16(w, os2->usWidthClass);
496 writeU16(w, 0); //fstype
497 writeU16(w, os2->ySubscriptXSize);
498 writeU16(w, os2->ySubscriptYSize);
499 writeU16(w, os2->ySubscriptXOffset);
500 writeU16(w, os2->ySubscriptYOffset);
501 writeU16(w, os2->ySuperscriptXSize);
502 writeU16(w, os2->ySuperscriptYSize);
503 writeU16(w, os2->ySuperscriptXOffset);
504 writeU16(w, os2->ySuperscriptYOffset);
505 writeU16(w, os2->yStrikeoutSize);
506 writeU16(w, os2->yStrikeoutPosition);
507 writeU16(w, os2->sFamilyClass);
508 writeU8(w, os2->panose_FamilyType);
509 writeU8(w, os2->panose_SerifStyle);
510 writeU8(w, os2->panose_Weight);
511 writeU8(w, os2->panose_Proportion);
512 writeU8(w, os2->panose_Contrast);
513 writeU8(w, os2->panose_StrokeVariation);
514 writeU8(w, os2->panose_ArmStyle);
515 writeU8(w, os2->panose_Letterform);
516 writeU8(w, os2->panose_Midline);
517 writeU8(w, os2->panose_XHeight);
518 writeU32(w, os2->ulCharRange[0]);
519 writeU32(w, os2->ulCharRange[1]);
520 writeU32(w, os2->ulCharRange[2]);
521 writeU32(w, os2->ulCharRange[3]);
522 writeU32(w, 0x53434244); //vendor
523 writeU16(w, os2->fsSelection);
524 writeU16(w, os2->fsFirstCharIndex);
525 writeU16(w, os2->fsLastCharIndex);
526 writeS16(w, os2->sTypoAscender);
527 writeS16(w, os2->sTypoDescender);
528 writeS16(w, os2->sTypoLineGap);
529 writeU16(w, os2->usWinAscent);
530 writeU16(w, os2->usWinDescent);
531 if(version<1) return;
532 writeU32(w, os2->ulCodePageRange1);
533 writeU32(w, os2->ulCodePageRange2);
534 if(version<2) return;
535 writeS16(w, os2->sxHeight);
536 writeS16(w, os2->sCapHeight);
537 writeU16(w, os2->usDefaultChar);
538 writeU16(w, os2->usBreakChar);
539 writeU16(w, os2->usMaxContext);
541 static void os2_dump(ttf_t*ttf)
543 table_os2_t*os2 = ttf->os2;
545 printf("os2->xAvgCharWidth: %d\n", os2->xAvgCharWidth);
546 printf("os2->usWeightClass: %d\n", os2->usWeightClass);
547 printf("os2->usWidthClass: %d\n", os2->usWidthClass);
548 printf("os2->ySubscriptXSize: %d\n", os2->ySubscriptXSize);
549 printf("os2->ySubscriptYSize: %d\n", os2->ySubscriptYSize);
550 printf("os2->ySubscriptXOffset: %d\n", os2->ySubscriptXOffset);
551 printf("os2->ySubscriptYOffset: %d\n", os2->ySubscriptYOffset);
552 printf("os2->ySuperscriptXSize: %d\n", os2->ySuperscriptXSize);
553 printf("os2->ySuperscriptYSize: %d\n", os2->ySuperscriptYSize);
554 printf("os2->ySuperscriptXOffset: %d\n", os2->ySuperscriptXOffset);
555 printf("os2->ySuperscriptYOffset: %d\n", os2->ySuperscriptYOffset);
556 printf("os2->yStrikeoutSize: %d\n", os2->yStrikeoutSize);
557 printf("os2->yStrikeoutPosition: %d\n", os2->yStrikeoutPosition);
558 printf("os2->sFamilyClass: %d\n", os2->sFamilyClass);
559 printf("os2->panose_FamilyType: %d\n", os2->panose_FamilyType);
560 printf("os2->panose_SerifStyle: %d\n", os2->panose_SerifStyle);
561 printf("os2->panose_Weight: %d\n", os2->panose_Weight);
562 printf("os2->panose_Proportion: %d\n", os2->panose_Proportion);
563 printf("os2->panose_Contrast: %d\n", os2->panose_Contrast);
564 printf("os2->panose_StrokeVariation: %d\n", os2->panose_StrokeVariation);
565 printf("os2->panose_ArmStyle: %d\n", os2->panose_ArmStyle);
566 printf("os2->panose_Letterform: %d\n", os2->panose_Letterform);
567 printf("os2->panose_Midline: %d\n", os2->panose_Midline);
568 printf("os2->panose_XHeight: %d\n", os2->panose_XHeight);
569 printf("os2->ulCharRange[0]: %d\n", os2->ulCharRange[0]);
570 printf("os2->ulCharRange[1]: %d\n", os2->ulCharRange[1]);
571 printf("os2->ulCharRange[2]: %d\n", os2->ulCharRange[2]);
572 printf("os2->ulCharRange[3]: %d\n", os2->ulCharRange[3]);
573 printf("os2->fsSelection: %d\n", os2->fsSelection);
574 printf("os2->fsFirstCharIndex: %d\n", os2->fsFirstCharIndex);
575 printf("os2->fsLastCharIndex: %d\n", os2->fsLastCharIndex);
576 printf("os2->sTypoAscender: %d\n", os2->sTypoAscender);
577 printf("os2->sTypoDescender: %d\n", os2->sTypoDescender);
578 printf("os2->sTypoLineGap: %d\n", os2->sTypoLineGap);
579 printf("os2->usWinAscent: %d\n", os2->usWinAscent);
580 printf("os2->usWinDescent: %d\n", os2->usWinDescent);
581 printf("os2->ulCodePageRange1: %d\n", os2->ulCodePageRange1);
582 printf("os2->ulCodePageRange2: %d\n", os2->ulCodePageRange2);
583 printf("os2->sxHeight: %d\n", os2->sxHeight);
584 printf("os2->sCapHeight: %d\n", os2->sCapHeight);
585 printf("os2->usDefaultChar: %d\n", os2->usDefaultChar);
586 printf("os2->usBreakChar: %d\n", os2->usBreakChar);
587 printf("os2->usMaxContext: %d\n", os2->usMaxContext);
589 static void os2_delete(ttf_t*ttf)
596 static table_maxp_t*maxp_new(ttf_t*ttf)
598 table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
600 if(ttf->num_glyphs) {
602 for(t=0;t<ttf->num_glyphs;t++) {
603 if(ttf->glyphs[t].num_points>max)
604 max = ttf->glyphs[t].num_points;
607 for(s=0;s<ttf->glyphs[t].num_points;s++) {
608 if(ttf->glyphs[t].points[s].flags&GLYPH_CONTOUR_END)
611 if(maxp->maxContours < contours)
612 maxp->maxContours = contours;
614 maxp->maxPoints = max;
616 /* we don't generate composite glyphs yet */
617 maxp->maxComponentPoints = 0;
618 maxp->maxComponentContours = 0;
622 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
624 U32 version = readU32(r);
625 ttf->num_glyphs = readU16(r);
626 /* according to freetype, older fonts (version<0x10000)
627 apparently only contain the number of glyphs. this is
628 rather rare, though. */
629 if(version<0x10000 && r->size==6) return 0;
632 msg("<warning> Truncated maxp table (version %d)", version);
634 table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
635 maxp->maxPoints = readU16(r);
636 maxp->maxContours = readU16(r);
637 maxp->maxComponentPoints = readU16(r);
638 maxp->maxComponentContours = readU16(r);
639 maxp->maxZones = readU16(r);
640 maxp->maxTwilightPoints = readU16(r);
641 maxp->maxStorage = readU16(r);
642 maxp->maxFunctionDefs = readU16(r);
643 maxp->maxInstructionDefs = readU16(r);
644 maxp->maxStackElements = readU16(r);
645 maxp->maxSizeOfInstructions = readU16(r);
646 maxp->maxComponentElements = readU16(r);
647 maxp->maxComponentDepth = readU16(r);
650 static void maxp_write(ttf_t*ttf, ttf_table_t*w)
652 table_maxp_t*maxp = ttf->maxp;
654 /* version 0.5 simplified maxp table */
655 writeU32(w, 0x00005000);
656 writeU16(w, ttf->num_glyphs);
659 writeU32(w, 0x10000); //version
660 writeU16(w, ttf->num_glyphs);
661 writeU16(w, maxp->maxPoints);
662 writeU16(w, maxp->maxContours);
663 writeU16(w, maxp->maxComponentPoints);
664 writeU16(w, maxp->maxComponentContours);
665 writeU16(w, maxp->maxZones);
666 writeU16(w, maxp->maxTwilightPoints);
667 writeU16(w, maxp->maxStorage);
668 writeU16(w, maxp->maxFunctionDefs);
669 writeU16(w, maxp->maxInstructionDefs);
670 writeU16(w, maxp->maxStackElements);
671 writeU16(w, maxp->maxSizeOfInstructions);
672 writeU16(w, maxp->maxComponentElements);
673 writeU16(w, maxp->maxComponentDepth);
675 static void maxp_dump(ttf_t*ttf)
677 table_maxp_t*maxp = ttf->maxp;
679 printf("maxp->maxPoints: %d\n", maxp->maxPoints);
680 printf("maxp->maxContours: %d\n", maxp->maxContours);
681 printf("maxp->maxComponentPoints: %d\n", maxp->maxComponentPoints);
682 printf("maxp->maxComponentContours: %d\n", maxp->maxComponentContours);
683 printf("maxp->maxZones: %d\n", maxp->maxZones);
684 printf("maxp->maxTwilightPoints: %d\n", maxp->maxTwilightPoints);
685 printf("maxp->maxStorage: %d\n", maxp->maxStorage);
686 printf("maxp->maxFunctionDefs: %d\n", maxp->maxFunctionDefs);
687 printf("maxp->maxInstructionDefs: %d\n", maxp->maxInstructionDefs);
688 printf("maxp->maxStackElements: %d\n", maxp->maxStackElements);
689 printf("maxp->maxSizeOfInstructions: %d\n", maxp->maxSizeOfInstructions);
690 printf("maxp->maxComponentElements: %d\n", maxp->maxComponentElements);
691 printf("maxp->maxComponentDepth: %d\n", maxp->maxComponentDepth);
693 static void maxp_delete(ttf_t*ttf)
700 static table_hea_t*hea_new(ttf_t*ttf)
702 table_hea_t*hea = rfx_calloc(sizeof(table_hea_t));
703 if(ttf->num_glyphs) {
705 for(t=0;t<ttf->num_glyphs;t++) {
706 if(ttf->glyphs[t].advance > hea->advanceWidthMax)
707 hea->advanceWidthMax = ttf->glyphs[t].advance;
708 if(ttf->glyphs[t].xmin < hea->minLeftSideBearing)
709 hea->minLeftSideBearing = ttf->glyphs[t].xmin;
710 if(ttf->glyphs[t].xmax < hea->minRightSideBearing)
711 hea->minRightSideBearing = ttf->glyphs[t].xmax;
712 int width = ttf->glyphs[t].xmax - ttf->glyphs[t].xmin;
713 if(width > hea->xMaxExtent)
714 hea->xMaxExtent = width;
720 static int hea_parse(memreader_t*r, ttf_t*ttf)
722 table_hea_t*hea = ttf->hea = rfx_calloc(sizeof(table_hea_t));
723 U32 version = readU32(r);
724 ttf->ascent = readS16(r);
725 ttf->descent = readS16(r);
726 ttf->lineGap = readS16(r);
727 hea->advanceWidthMax = readU16(r);
728 hea->minLeftSideBearing = readS16(r);
729 hea->minRightSideBearing = readS16(r);
730 hea->xMaxExtent = readS16(r);
731 hea->caretSlopeRise = readS16(r);
732 hea->caretSlopeRun = readS16(r);
733 hea->caretOffset = readS16(r);
734 readS16(r); //reserved[0]
735 readS16(r); //reserved[1]
736 readS16(r); //reserved[2]
737 readS16(r); //reserved[3]
738 S16 metricDataFormat = readS16(r); //should be 0
739 if(metricDataFormat!=0) {
740 msg("<warning> Unknown metric format %d", metricDataFormat);
742 int num_advances = readU16(r);
743 if(num_advances > ttf->num_glyphs) {
744 msg("<warning> bad number of horizontal metrics: %d", num_advances);
745 num_advances = ttf->num_glyphs;
749 static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances)
751 table_hea_t*hea = ttf->hea;
752 writeU32(w, 0x00010000);
753 writeS16(w, ttf->ascent);
754 writeS16(w, ttf->descent);
755 writeS16(w, ttf->lineGap);
756 writeU16(w, hea->advanceWidthMax);
757 writeS16(w, hea->minLeftSideBearing);
758 writeS16(w, hea->minRightSideBearing);
759 writeS16(w, hea->xMaxExtent);
760 writeS16(w, hea->caretSlopeRise);
761 writeS16(w, hea->caretSlopeRun);
762 writeS16(w, hea->caretOffset);
763 writeS16(w, 0); //reserved
764 writeS16(w, 0); //reserved
765 writeS16(w, 0); //reserved
766 writeS16(w, 0); //reserved
767 writeS16(w, 0); //metricDataFormat
768 writeU16(w, num_advances);
771 static void hea_dump(ttf_t*ttf)
773 table_hea_t*hea = ttf->hea;
775 const char*dir = ttf->is_vertical?"v":"h";
776 printf("%shea->ascent: %d\n", dir, ttf->ascent);
777 printf("%shea->descent: %d\n", dir, ttf->descent);
778 printf("%shea->lineGap: %d\n", dir, ttf->lineGap);
779 printf("%shea->advanceWidthMax: %d\n", dir, hea->advanceWidthMax);
780 printf("%shea->minLeftSideBearing: %d\n", dir, hea->minLeftSideBearing);
781 printf("%shea->minRightSideBearing: %d\n", dir, hea->minRightSideBearing);
782 printf("%shea->xMaxExtent: %d\n", dir, hea->xMaxExtent);
783 printf("%shea->caretSlopeRise: %d\n", dir, hea->caretSlopeRise);
784 printf("%shea->caretSlopeRun: %d\n", dir, hea->caretSlopeRun);
785 printf("%shea->caretOffset: %d\n", dir, hea->caretOffset);
787 static void hea_delete(ttf_t*ttf)
795 static void mtx_parse(memreader_t*r, ttf_t*ttf, int num_advances)
799 if(num_advances > r->size/4)
800 num_advances = r->size/4;
801 for(t=0;t<num_advances;t++) {
802 old_advance = ttf->glyphs[t].advance = readU16(r);
803 ttf->glyphs[t].bearing = readS16(r);
805 int rest = (r->size - num_advances*4)/2;
806 if(ttf->num_glyphs < num_advances+rest) {
807 rest = ttf->num_glyphs-num_advances;
809 for(t=0;t<rest;t++) {
810 ttf->glyphs[t].advance = old_advance;
811 ttf->glyphs[t].bearing = readS16(r);
814 static int mtx_write(ttf_t*ttf, ttf_table_t*w)
816 int num_advances = ttf->num_glyphs;
817 if(ttf->num_glyphs>=2) {
819 for(t=ttf->num_glyphs-1;t>0;t--) {
820 if(ttf->glyphs[t-1].advance !=
821 ttf->glyphs[t].advance) break;
823 /* we need to store all individual advances as well
824 as one entry for the constant */
829 for(t=0;t<num_advances;t++) {
830 writeU16(w, ttf->glyphs[t].advance);
831 writeU16(w, ttf->glyphs[t].bearing);
833 for(;t<ttf->num_glyphs;t++) {
834 writeU16(w, ttf->glyphs[t].bearing);
839 static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size)
842 int num = ttf->num_glyphs+1;
843 U32*locations = rfx_calloc(num*sizeof(U32));
846 char warn_unsorted = 1;
848 if(num*4 > r->size) {
849 msg("<warning> Short 'loca' table (32 bit): %d/%d", r->size/4, num);
852 if(num*4 < r->size) {
853 msg("<warning> Extraneous data (%d bytes) in 'loca' table (32 bit)", r->size-num*4);
856 locations[t] = loc = readU32(r);
857 if(lastloc > loc && warn_unsorted) {
858 msg("<warning> Unsorted 'loca' table (32 bit)");
864 if(num*2 > r->size) {
865 msg("<warning> Short 'loca' table (16 bit)");
868 if(num*2 < r->size) {
869 msg("<warning> Extraneous data (%d bytes) in 'loca' table (16 bit)", r->size-num*2);
872 locations[t] = loc = readU16(r)*2;
873 if(lastloc > loc && warn_unsorted) {
874 msg("<warning> Unsorted 'loca' table");
882 static int loca_write(ttf_t*ttf, ttf_table_t*w, U32*locations)
886 for(t=0;t<=ttf->num_glyphs;t++) {
887 if(locations[t]>=0x20000 || (locations[t]&1)) {
894 for(t=0;t<=ttf->num_glyphs;t++) {
895 writeU32(w, locations[t]);
899 for(t=0;t<=ttf->num_glyphs;t++) {
900 writeU16(w, locations[t]/2);
906 static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int glyphnr)
908 ttfglyph_t*glyph = &ttf->glyphs[glyphnr];
912 endpoints = malloc(sizeof(U16)*num_contours);
915 for(s=0;s<num_contours;s++) {
916 int pos = endpoints[s] = readU16(r);
918 msg("<warning> Unsorted endpoints array (len:%d) last=%d now=%d", s, pos, lastpos);
923 U16 code_len = readU16(r);
925 glyph->code = malloc(sizeof(U16)*code_len);
926 readBlock(r, glyph->code, code_len);
927 glyph->code_size = code_len;
933 /*msg("<notice> TTF Glyph %d) code_size=%d num_contours=%d glyph->num_points=%d %d/%d/%d/%d",
934 glyphnr, code_len, num_contours, glyph->num_points,
935 xmin, ymin, xmax, ymax);*/
936 INIT_READ(fx, r->mem, r->size, r->pos);
937 INIT_READ(fy, r->mem, r->size, r->pos);
939 glyph->num_points = endpoints[num_contours-1] + 1;
940 glyph->points = rfx_calloc(sizeof(ttfpoint_t)*glyph->num_points);
942 /* parse flag array (1st pass- to determine start of coordinates) */
944 while(num<glyph->num_points) {
947 msg("<error> Bad flags in glyph outline: %02x (at pos %d)", flag, num);
950 glyph->num_points = 0;
956 if(count+num>glyph->num_points) {
957 msg("<warning> Bad count (%d) in glyph (%d) (at pos %d)", count, glyphnr, num);
958 count = glyph->num_points-num;
963 /* parse flag array (2nd pass) and x coordinates */
968 int bytepos = r->pos;
969 while(num<glyph->num_points) {
970 U8 flag = readU8(&fx);
971 int count = flag&8?readU8(&fx)+1:1;
972 count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
975 if(contour_pos<num_contours && num==endpoints[contour_pos]) {
980 if((flag&0x12) == 0x12) x += readU8(r);
981 else if((flag&0x12) == 0x02) x -= readU8(r);
982 else if((flag&0x12) == 0x00) x += readS16(r);
984 glyph->points[num].x = x;
985 U8 f = flag&GLYPH_ON_CURVE;
986 if(is_start) f|=GLYPH_CONTOUR_START;
987 if(is_end) f|=GLYPH_CONTOUR_END;
988 glyph->points[num].flags = f;
994 /* parse flag array (3rd pass) and y coordinates */
997 while(num<glyph->num_points) {
998 U8 flag = readU8(&fy);
999 int count = flag&8?readU8(&fy)+1:1;
1000 count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
1002 if((flag&0x24) == 0x24) y += readU8(r);
1003 else if((flag&0x24) == 0x04) y -= readU8(r);
1004 else if((flag&0x24) == 0x00) y += readS16(r);
1005 glyph->points[num].y = y;
1012 static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
1015 char warn_about_compound_glyphs=0;
1016 for(t=0;t<ttf->num_glyphs;t++) {
1017 INIT_READ(r, rr->mem, rr->size, loca[t]);
1018 if(loca[t]==loca[t+1] || loca[t]==r.size)
1019 continue; //empty glyph
1020 if(r.pos+10>r.size) {
1021 msg("<warning> Truncated glyph entry %d/%d (or bad loca entry %d/%d, next loca: %d)",
1022 t, ttf->num_glyphs, loca[t], r.size, loca[t+1]);
1025 S16 num_contours = readS16(&r);
1026 ttf->glyphs[t].xmin = readS16(&r);
1027 ttf->glyphs[t].ymin = readS16(&r);
1028 ttf->glyphs[t].xmax = readS16(&r);
1029 ttf->glyphs[t].ymax = readS16(&r);
1031 if(num_contours<0) {
1032 if(warn_about_compound_glyphs)
1033 msg("<error> Compound glyphs not supported yet");
1034 warn_about_compound_glyphs=0;
1036 if(!parse_simple_glyph(ttf, &r, num_contours, t))
1042 void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
1044 /* endpoints array */
1046 for(s=0;s<g->num_points;s++) {
1047 if(g->points[s].flags&GLYPH_CONTOUR_END)
1052 writeU16(w, g->code_size);
1054 writeBlock(w, g->code, g->code_size);
1061 for(s=0;s<g->num_points;s++) {
1062 ttfpoint_t*p = &g->points[s];
1063 int dx = p->x - lastx;
1064 int dy = p->y - lasty;
1065 U8 flags = p->flags&GLYPH_ON_CURVE;
1068 } else if(dx<0 && dx>=-255) {
1070 } else if(dx>0 && dx<=255) {
1075 } else if(dy<0 && dy>=-255) {
1077 } else if(dy>0 && dy<=255) {
1080 if(flags == lastflag && flagcount<255) {
1085 writeU8(w, lastflag|8);
1086 writeU8(w, flagcount);
1088 writeU8(w, lastflag);
1099 writeU8(w, lastflag|8);
1100 writeU8(w, flagcount);
1102 writeU8(w, lastflag);
1107 int bytepos = w->len;
1108 for(s=0;s<g->num_points;s++) {
1109 ttfpoint_t*p = &g->points[s];
1110 int dx = p->x - lastx;
1111 if(dx>32767 || dx<-32768) {
1112 msg("<error> Coordinate overflow in glyph");
1115 if(dx>0 && dx<=255) writeU8(w, dx);
1116 else if(dx<0 && dx>=-255) writeU8(w, -dx);
1117 else if(dx) writeS16(w, dx);
1121 for(s=0;s<g->num_points;s++) {
1122 ttfpoint_t*p = &g->points[s];
1123 int dy = p->y - lasty;
1124 if(dy>32767 || dy<-32768) {
1125 msg("<error> Coordinate overflow in glyph");
1128 if(dy>0 && dy<=255) writeU8(w, dy);
1129 else if(dy<0 && dy>=-255) writeU8(w, -dy);
1130 else if(dy) writeS16(w, dy);
1133 U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
1135 U32*locations = malloc(sizeof(U32)*(ttf->num_glyphs+1));
1137 for(t=0;t<ttf->num_glyphs;t++) {
1138 locations[t] = w->len;
1139 ttfglyph_t*g = &ttf->glyphs[t];
1141 int num_contours = 0;
1142 for(s=0;s<g->num_points;s++) {
1143 if(g->points[s].flags&GLYPH_CONTOUR_END)
1146 writeS16(w, num_contours?num_contours:1);
1147 writeS16(w, g->xmin);
1148 writeS16(w, g->ymin);
1149 writeS16(w, g->xmax);
1150 writeS16(w, g->ymax);
1153 /* some ttf parsers can't deal with zero contours, so in the case
1154 of an empty glyph, write a single point (0,0) */
1155 writeU16(w, 0); //endpoint of 1st contour
1156 writeU16(w, g->code_size);
1158 writeBlock(w, g->code, g->code_size);
1159 writeU8(w, 0x31); //flag (xy=(0,0),on curve)
1161 write_simple_glyph(w, g);
1164 locations[t] = w->len;
1167 void glyf_dump(ttf_t* ttf)
1169 if(!ttf->glyphs) return;
1171 for(t=0;t<ttf->num_glyphs;t++) {
1172 ttfglyph_t*g = &ttf->glyphs[t];
1173 printf("glyph %d)\n", t);
1174 printf(" advance=%d\n", g->advance);
1175 printf(" bearing=%d\n", g->bearing);
1176 printf(" bbox=(%d/%d/%d/%d)\n", g->xmin, g->ymin, g->xmax, g->ymax);
1177 printf(" points=(");
1179 for(s=0;s<g->num_points;s++) {
1181 printf("%d/%d/0x%02x", g->points[s].x, g->points[s].y, g->points[s].flags);
1185 hexdump(g->code, g->code_size, " ");
1188 void glyf_delete(ttf_t* ttf)
1193 for(t=0;t<ttf->num_glyphs;t++) {
1194 if(ttf->glyphs[t].code) {
1195 free(ttf->glyphs[t].code);
1196 ttf->glyphs[t].code = 0;
1198 if(ttf->glyphs[t].points) {
1199 free(ttf->glyphs[t].points);
1200 ttf->glyphs[t].points = 0;
1203 free(ttf->glyphs);ttf->glyphs=0;
1206 static void grow_unicode(ttf_t*ttf, int index)
1210 ttf->unicode = rfx_calloc(sizeof(ttf->unicode[0])*size);
1211 } else if(ttf->unicode_size<size) {
1212 ttf->unicode = rfx_realloc(ttf->unicode, sizeof(ttf->unicode[0])*size);
1213 memset(ttf->unicode+ttf->unicode_size, 0, sizeof(ttf->unicode[0])*(size - ttf->unicode_size));
1215 ttf->unicode_size = size;
1217 void cmap_parse(memreader_t*r, ttf_t*ttf)
1219 readU16(r); // version (0)
1220 int num_subtables = readU16(r);
1222 if(r->pos+num_subtables*8 > r->size) {
1223 msg("<warning> CMap overflow");
1224 num_subtables = (r->size-r->pos)/8;
1227 for(t=0;t<num_subtables;t++) {
1228 U16 platform = readU16(r);
1229 U16 encoding = readU16(r);
1230 U32 offset = readU32(r);
1231 if(offset>r->size) {
1232 msg("<warning> CMAP table %d %d is out of bounds (%d)", platform, encoding, offset);
1236 int is_unicode = platform==0 ||
1237 platform==3 && encoding == 1 ||
1238 platform==3 && encoding == 10;
1243 INIT_READ(t, r->mem, r->size, offset);
1244 U16 format = readU16(&t);
1245 int length = readU16(&t);
1246 U16 language = readU16(&t);
1249 msg("<warning> Language code %02x in unicode mapping", language);
1254 if(t.pos+length > t.size) {
1255 msg("<warning> overflow in format 0 cmap table");
1258 data = malloc(num*sizeof(unicode_t));
1260 grow_unicode(ttf, num);
1261 for(s=0;s<num;s++) {
1262 ttf->unicode[s] = readU8(&t);
1264 } else if(format == 4) {
1265 U16 segment_count = readU16(&t);
1266 if(segment_count&1) {
1267 msg("<error> Bad segmentx2 count %d", segment_count);
1271 readU16(&t); //searchrange
1272 readU16(&t); //entry selector
1273 readU16(&t); //range shift
1274 INIT_READ(r_end, t.mem, t.size, t.pos);
1275 INIT_READ(r_start, t.mem, t.size, t.pos+2+segment_count*2);
1276 INIT_READ(r_delta, t.mem, t.size, t.pos+2+segment_count*4);
1277 INIT_READ(r_range, t.mem, t.size, t.pos+2+segment_count*6);
1278 int glyphmap_start = t.pos+2+segment_count*8;
1280 for(s=0;s<segment_count;s++) {
1281 U16 start = readU16(&r_start);
1282 U16 end = readU16(&r_end);
1283 U16 delta = readU16(&r_delta);
1284 U16 range = readU16(&r_range);
1285 if(start==0xffff && end==0xffff && delta==1) {
1286 /* this is a common (maybe even required) occurence in fonts
1287 which explicitly map "unicode undefined" (0xffff) to
1288 "glyph undefined" (0).
1289 We don't want to blow our unicode table up to 65536 just
1290 because of this, so ignore this entry.
1294 grow_unicode(ttf, end);
1297 for(u=start;u<=end;u++) {
1298 ttf->unicode[u] = (u + delta) & 0xffff;
1301 INIT_READ(g, t.mem, t.size, r_range.pos-2+range);
1302 for(u=start;u<=end;u++) {
1303 ttf->unicode[u] = readU16(&g);
1310 static int segment_size(unicode_t*unicode, int pos, int size)
1314 for(s=pos;s<size;s++) {
1318 /* a segment costs us 8 bytes, so for more than 4 consecutive
1319 zero entries (16 bit each) in the glyph index array,
1320 it pays off to start a new segment */
1324 s -= count; // go to the last filled in entry
1329 void cmap_write(ttf_t* ttf, ttf_table_t*w)
1331 writeU16(w, 0); //version
1332 writeU16(w, 2); //two tables
1334 writeU16(w, 0); //platform (unicode)
1335 writeU16(w, 3); //encoding (unicode 2.0)
1336 writeU32(w, 20); //offset
1338 writeU16(w, 3); //platform (windows)
1339 writeU16(w, 1); //encoding (unicode basic multilingual plane UCS-2)
1340 writeU32(w, 20); //offset
1342 writeU16(w, 4); // format=4
1343 int length_pos = w->len;
1344 writeU16(w, 0); // length: we don't know yet
1345 writeU16(w, 0); // language (n/a for unicode)
1346 int num_segments_pos = w->len;
1347 writeU16(w, 0); //number of segments: we don't know yet either
1348 writeU16(w, 0); //searchrange
1349 writeU16(w, 0); //entry selector
1350 writeU16(w, 0); //range shift
1354 while(pos < ttf->unicode_size) {
1355 if(!ttf->unicode[pos]) {
1359 int s = segment_size(ttf->unicode, pos, ttf->unicode_size);
1364 num_segments++; // account for 0xffff mapping
1367 int end_pos = w->len;
1368 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
1369 writeU16(w, 0); //reserved byte
1370 int start_pos = w->len;
1371 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //start array
1372 int delta_pos = w->len;
1373 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //delta array
1374 int range_pos = w->len;
1375 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //range array
1377 w->data[num_segments_pos]=(num_segments*2)>>8;
1378 w->data[num_segments_pos+1]=(num_segments*2);
1382 while(pos < ttf->unicode_size) {
1383 if(!ttf->unicode[pos]) {
1387 U16 end = segment_size(ttf->unicode, pos, ttf->unicode_size);
1388 w->data[end_pos++]=end>>8;
1389 w->data[end_pos++]=end;
1390 w->data[start_pos++]=pos>>8;
1391 w->data[start_pos++]=pos;
1393 U16 delta = ttf->unicode[pos]-pos;
1395 for(s=pos+1;s<=end;s++) {
1396 U16 delta2 = ttf->unicode[pos]-pos;
1407 range = w->len - range_pos+num_segments*2;
1408 for(s=pos;s<=end;s++) {
1409 writeU16(w, ttf->unicode[s]);
1412 w->data[delta_pos++]=delta>>8;
1413 w->data[delta_pos++]=delta;
1414 w->data[range_pos++]=range>>8;
1415 w->data[range_pos++]=range;
1420 /* write out a mapping from 0xffff to 0- seems to be required
1421 by some libraries (e.g. fonttools) */
1422 w->data[end_pos++]=0xff;
1423 w->data[end_pos++]=0xff;
1424 w->data[start_pos++]=0xff;
1425 w->data[start_pos++]=0xff;
1426 w->data[delta_pos++]=0;
1427 w->data[delta_pos++]=1;
1428 w->data[range_pos++]=0;
1429 w->data[range_pos++]=0;
1431 w->data[length_pos]=(w->len-20)>>8;
1432 w->data[length_pos+1]=w->len-20;
1434 void cmap_delete(ttf_t*ttf)
1440 ttf->unicode_size=0;
1442 void name_parse(memreader_t*r, ttf_t*ttf)
1444 U16 format = readU16(r);
1445 U16 count = readU16(r);
1446 U16 offset = readU16(r);
1449 for(t=0;t<count;t++) {
1450 U16 platform = readU16(r);
1451 U16 encoding = readU16(r);
1452 U16 language = readU16(r);
1453 U16 name_id = readU16(r);
1454 U16 len = readU16(r);
1455 U16 offset_2 = readU16(r);
1456 /*printf("%d %d %d %d at %d, %d bytes:", platform, encoding, language, name_id, offset+offset_2, len);
1458 for(s=0;s<len;s++) {
1459 printf("%c", r->mem[offset+offset_2+s]);
1464 void name_write(ttf_t*ttf, ttf_table_t*table)
1466 writeU16(table, 0); //format
1467 writeU16(table, 1); //count
1469 writeU16(table, offset); //offset
1471 writeU16(table, 1); //platform id
1472 writeU16(table, 0); //encoding id
1473 writeU16(table, 0); //language
1474 writeU16(table, 4); //4: full name
1475 int len = strlen(ttf->name);
1476 writeU16(table, len);
1477 writeU16(table, table->len+2 - offset);
1479 for(t=0;t<len;t++) {
1480 writeU8(table, ttf->name[t]);
1483 void name_delete(ttf_t*ttf)
1489 static int ttf_parse_tables(ttf_t*ttf)
1493 table = ttf_find_table(ttf, TAG_HEAD);
1495 msg("<error> Font has no head table");
1498 INIT_READ(m, table->data, table->len, 0);
1499 int loc_index = head_parse(ttf, &m);
1500 ttf_table_delete(ttf, table);
1502 table = ttf_find_table(ttf, TAG_MAXP);
1504 msg("<error> Font has no maxp table");
1507 INIT_READ(m2, table->data, table->len, 0);
1508 ttf->maxp = maxp_parse(ttf, &m2);
1509 ttf_table_delete(ttf, table);
1511 if(!ttf->num_glyphs) {
1512 msg("<error> Invalid number of characters");
1515 ttf->glyphs = rfx_calloc(sizeof(ttfglyph_t)*ttf->num_glyphs);
1517 table = ttf_find_table(ttf, TAG_OS2);
1519 INIT_READ(m, table->data, table->len, 0);
1520 ttf->os2 = os2_parse(&m);
1521 ttf_table_delete(ttf, table);
1524 table = ttf_find_table(ttf, TAG_HHEA);
1526 INIT_READ(m, table->data, table->len, 0);
1527 int num_advances = hea_parse(&m, ttf);
1528 ttf_table_delete(ttf, table);
1530 table = ttf_find_table(ttf, TAG_HMTX);
1532 INIT_READ(m, table->data, table->len, 0);
1533 mtx_parse(&m, ttf, num_advances);
1534 ttf_table_delete(ttf, table);
1537 table = ttf_find_table(ttf, TAG_VHEA);
1540 INIT_READ(m, table->data, table->len, 0);
1541 int num_advances = hea_parse(&m, ttf);
1542 ttf_table_delete(ttf, table);
1544 table = ttf_find_table(ttf, TAG_VMTX);
1546 INIT_READ(m, table->data, table->len, 0);
1547 mtx_parse(&m, ttf, num_advances);
1548 ttf_table_delete(ttf, table);
1551 msg("<error> Font contains neither HHEA nor VHEA");
1554 table = ttf_find_table(ttf, TAG_LOCA);
1556 INIT_READ(m, table->data, table->len, 0);
1557 U32*loca = loca_parse(&m, ttf, loc_index);
1558 ttf_table_delete(ttf, table);
1559 table = ttf_find_table(ttf, TAG_GLYF);
1561 INIT_READ(m, table->data, table->len, 0);
1562 glyf_parse(&m, ttf, loca);
1563 ttf_table_delete(ttf, table);
1568 table = ttf_find_table(ttf, TAG_CMAP);
1570 INIT_READ(m, table->data, table->len, 0);
1571 cmap_parse(&m, ttf);
1572 ttf_table_delete(ttf, table);
1575 table = ttf_find_table(ttf, TAG_NAME);
1577 INIT_READ(m, table->data, table->len, 0);
1578 name_parse(&m, ttf);
1579 ttf_table_delete(ttf, table);
1584 static void ttf_collapse_tables(ttf_t*ttf)
1588 table = ttf_addtable(ttf, TAG_MAXP);
1589 maxp_write(ttf, table);
1592 table = ttf_addtable(ttf, TAG_OS2);
1593 os2_write(ttf, table);
1596 if(!ttf->is_vertical) {
1597 table = ttf_addtable(ttf, TAG_HMTX);
1598 int num_advances = mtx_write(ttf, table);
1599 table = ttf_addtable(ttf, TAG_HHEA);
1600 hea_write(ttf, table, num_advances);
1602 table = ttf_addtable(ttf, TAG_VMTX);
1603 int num_advances = mtx_write(ttf, table);
1604 table = ttf_addtable(ttf, TAG_VHEA);
1605 hea_write(ttf, table, num_advances);
1609 if(ttf->num_glyphs) {
1610 table = ttf_addtable(ttf, TAG_CMAP);
1611 cmap_write(ttf, table);
1614 table = ttf_addtable(ttf, TAG_GLYF);
1615 U32*locations = glyf_write(ttf, table);
1618 table = ttf_addtable(ttf, TAG_LOCA);
1619 loca_size = loca_write(ttf, table, locations);
1624 table = ttf_addtable(ttf, TAG_NAME);
1625 name_write(ttf, table);
1629 table = ttf_addtable(ttf, TAG_HEAD);
1630 head_write(ttf, table, loca_size);
1636 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1637 ttf->version = VERSION_1_0;
1640 ttf_t* ttf_load(void*data, int length)
1642 INIT_READ(r,data,length, 0);
1645 msg("<error> Truncated Truetype file (%d bytes)", length);
1649 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1650 ttf->version = readU32(&r);
1651 if(ttf->version == TTCFTAG) {
1652 /* a ttc collection is a number of truetype fonts
1653 packaged together */
1655 msg("<error> Truncated TTC file (%d bytes)", length);
1658 U32 ttcf_version = readU32(&r); // 0x00000100: v1.0, 0x00000200: v2.0, includes DSIG table
1659 U32 num_fonts = readU32(&r); // number of fonts
1660 U32 font1_position = readU32(&r);
1661 if(font1_position+12 > length) {\
1662 msg("<error> Truncated TTC file (%d bytes, first font at %d)", length, font1_position);
1665 r.pos = font1_position;
1666 ttf->version = readU32(&r);
1669 int num_tables = readU16(&r);
1671 readU16(&r); //search range
1672 readU16(&r); //entry selector
1673 readU16(&r); //range shift
1675 if(num_tables*16 > length) {
1676 msg("<error> Truncated TTC file (table entries: %d)", num_tables);
1677 if(ttf->version != OPENTYPE &&
1678 ttf->version != TRUETYPE_MACOS &&
1679 ttf->version != VERSION_1_0) {
1680 // bad table length, weird version. This is probably not a ttf file.
1685 U32*table_data = malloc(16*num_tables);
1687 for(t=0;t<num_tables*4;t++) {
1688 table_data[t] = readU32(&r);
1690 for(t=0;t<num_tables;t++) {
1691 U32 tag = table_data[t*4];
1692 U32 checksum = table_data[t*4+1];
1693 U32 pos = table_data[t*4+2];
1694 U32 len = table_data[t*4+3];
1696 if(pos+len > length) {
1697 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);
1699 U8*mem = malloc(len);
1701 readBlock(&r, mem, len);
1703 ttf_table_t*table = ttf_addtable(ttf, tag);
1705 table->len = table->memsize = len;
1707 U32 checksum2 = ttf_table_checksum(table);
1708 if(checksum2!=checksum) {
1709 msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x",
1710 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1711 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1712 len, checksum2, checksum);
1719 if(!ttf_parse_tables(ttf))
1724 void ttf_create_truetype_tables(ttf_t*ttf)
1727 ttf->head = head_new(ttf);
1729 ttf->maxp = maxp_new(ttf);
1731 ttf->hea = hea_new(ttf);
1733 ttf->os2 = os2_new(ttf);
1735 ttf_table_t* ttf_write(ttf_t*ttf)
1737 ttf_collapse_tables(ttf);
1739 ttf_table_t*file = ttf_table_new(0);
1740 writeU32(file, VERSION_1_0);
1742 /* write number of tables */
1744 ttf_table_t*t = ttf->tables;
1749 writeU16(file, num_tables);
1751 /* write search range */
1752 int tmp = num_tables;
1753 int search_range = 0;
1760 writeU16(file, search_range);
1762 /* write entry selector */
1763 int entry_selector = 0;
1768 writeU16(file, entry_selector);
1770 /* write range shift */
1771 int range_shift = num_tables*16 - search_range;
1772 writeU16(file, range_shift);
1774 /* write table dictionary */
1775 int table_dictionary_pos = file->len;
1776 int data_pos = file->len + num_tables*16;
1777 for(t=ttf->tables;t;t=t->next) {
1778 writeU32(file, t->id);
1779 writeU32(file, ttf_table_checksum(t));
1780 writeU32(file, data_pos);
1781 writeU32(file, t->len);
1783 data_pos += (-t->len)&3; //pad
1788 U8 zero[4]={0,0,0,0};
1789 for(t=ttf->tables;t;t=t->next) {
1790 if(t->id == TAG_HEAD)
1791 head_pos = file->len;
1792 writeBlock(file, t->data, t->len);
1793 writeBlock(file, zero, (-t->len)&3); //pad
1795 U32 checksum = 0xb1b0afba - ttf_table_checksum(file);
1796 U8*checksum2 = file->data + head_pos + 8;
1797 checksum2[0] = checksum>>24;
1798 checksum2[1] = checksum>>16;
1799 checksum2[2] = checksum>>8;
1800 checksum2[3] = checksum>>0;
1803 void ttf_save(ttf_t*ttf, const char*filename)
1805 ttf_table_t* t = ttf_write(ttf);
1806 FILE*fi = fopen(filename, "wb");
1811 fwrite(t->data, t->len, 1, fi);
1813 ttf_table_delete(0, t);
1815 void ttf_dump(ttf_t*ttf)
1817 msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
1818 ttf_table_t*table = ttf->tables;
1820 U32 tag = table->id;
1821 msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)",
1822 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1823 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
1824 table = table->next;
1826 //ttf_table_dump(ttf_find_table(ttf, TAG_MAXP));
1834 void ttf_destroy(ttf_t*ttf)
1836 ttf_table_t*table = ttf->tables;
1838 ttf_table_t*next = table->next;
1852 int main(int argn, const char*argv[])
1854 setConsoleLogging(7);
1855 const char*filename = "comic.ttf";
1858 //msg("<notice> Loading %s", filename);
1859 memfile_t*m = memfile_open(filename);
1860 ttf_t*ttf = ttf_load(m->data, m->len);
1861 ttf->name = strdup("testfont");
1865 //printf("os2 version: %04x (%d), maxp size: %d\n",
1866 // ttf->os2->version, ttf->os2->size, ttf->maxp->size);
1867 ttf_save(ttf, "output.ttf");