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 */
31 #define TTCFTAG 0x74746366
33 #define OPENTYPE 0x4f54544f
34 #define TRUETYPE_MACOS 0x74727565
35 #define VERSION_1_0 0x00010000
37 #define TAG_OS2 0x4f532f32
38 #define TAG_CMAP 0x636d6170
39 #define TAG_GLYF 0x676c7966 //required for non opentype
40 #define TAG_HEAD 0x68656164 //required
41 #define TAG_HHEA 0x68686561 //required
42 #define TAG_HMTX 0x686d7478 //required
43 #define TAG_VHEA 0x86686561
44 #define TAG_VMTX 0x866d7478
45 #define TAG_KERN 0x6b65726e
46 #define TAG_LOCA 0x6c6f6361 //required for non opentype
47 #define TAG_MAXP 0x6d617870 //required
48 #define TAG_NAME 0x6e616d65
49 #define TAG_POST 0x706f7374
50 #define TAG_CFF 0x43464620 //required for opentype
53 fpgm - assembly instructions
54 prep - assembly instructions
55 cvt - constant value table
56 gasp - gridfitting procedure
59 static U32 checksum_block(U8*_data, int len)
65 int len_minus_4 = len-4;
66 for(pos=0;pos<=len_minus_4;pos+=4) {
67 sum += data[pos]<<24|data[pos+1]<<16|data[pos+2]<<8|data[pos+3];
70 if(left == 1) sum+= data[pos+0]<<24;
71 if(left == 2) sum+= data[pos+0]<<24|data[pos+1]<<16;
72 if(left == 3) sum+= data[pos+0]<<24|data[pos+1]<<16|data[pos+2]<<8;
76 typedef struct _memreader {
82 static U8 readU8(memreader_t*r)
84 return r->mem[r->pos++];
86 static inline U16 readU16(memreader_t*r)
88 if(r->pos+2>r->size) return 0;
89 U16 val = r->mem[r->pos]<<8|
94 static S16 readS16(memreader_t*r)
96 return (S16)readU16(r);
98 static U32 readU32(memreader_t*r)
100 if(r->pos+4>r->size) return 0;
101 U32 val = r->mem[r->pos]<<24|
102 r->mem[r->pos+1]<<16|
108 static void readBlock(memreader_t*r, void*dest, int len)
110 int remaining = r->size-r->pos;
111 if(len > remaining) {
112 memcpy(dest, r->mem+r->pos, remaining);
113 memset(dest+remaining, 0, len - remaining);
116 memcpy(dest, r->mem+r->pos, len);
120 #define INIT_READ(r,data,length,pos) memreader_t r = {(data),(pos),(length)};
122 static void expand(ttf_table_t*w, int newsize)
124 int v1 = (newsize+63)&~63;
125 int v2 = w->len + w->len / 2;
126 w->memsize = v1>v2?v1:v2;
127 w->data = rfx_realloc(w->data, w->memsize);
129 static inline void writeU8(ttf_table_t*w, unsigned char b)
131 if(w->memsize<w->len+1)
133 w->data[w->len++] = b;
135 static inline void writeU16(ttf_table_t*w, unsigned short v)
137 if(w->memsize<w->len+2)
139 w->data[w->len++] = v>>8;
140 w->data[w->len++] = v;
142 #define writeS16 writeU16
143 static inline void writeU32(ttf_table_t*w, unsigned long v)
145 if(w->memsize<w->len+4)
147 w->data[w->len++] = v>>24;
148 w->data[w->len++] = v>>16;
149 w->data[w->len++] = v>>8;
150 w->data[w->len++] = v;
152 static inline void writeBlock(ttf_table_t*w, void*data, int len)
154 if(w->memsize<w->len+len)
155 expand(w, w->len+len);
156 memcpy(w->data+w->len, data, len);
160 ttf_table_t*ttf_table_new(U32 id)
162 ttf_table_t*t = rfx_calloc(sizeof(ttf_table_t));
167 ttf_table_t*ttf_addtable(ttf_t*ttf, U32 id)
169 ttf_table_t*t = ttf_table_new(id);
171 ttf_table_t*before,*after=0;
172 for(before=ttf->tables; before&&before->id<id; before=before->next) {
175 if(before && before->id == id) {
176 msg("<error> Error: duplicate table %08x", id);
184 t->next = ttf->tables;
188 t->next = after->next;
195 ttf_table_t*ttf_find_table(ttf_t*ttf, U32 id)
197 ttf_table_t*table = ttf->tables;
205 void ttf_table_delete(ttf_t*ttf, ttf_table_t*table)
207 if(ttf && ttf->tables == table) {
208 ttf->tables = table->next;
211 table->prev->next = table->next;
213 table->next->prev = table->prev;
217 U32 ttf_table_checksum(ttf_table_t*t)
219 U32 checksum = checksum_block(t->data, t->len);
220 if(t->id==TAG_HEAD && t->len>=12) {
221 /* the checksum for the HEAD table is calculated by masking out
222 the checksumadjust field */
223 U32 adjust = t->data[8]<<24|t->data[9]<<16|t->data[10]<<8|t->data[11];
228 static U8 printable(U8 a)
230 if(a<32 || a==127) return '.';
233 static void hexdump(U8*data, int len, const char*prefix)
237 printf("%s -=> ",prefix);
239 printf("%02x ", data[t]);
240 ascii[t&15] = printable(data[t]);
241 if((t && ((t&15)==15)) || (t==len-1))
245 for(s=p-1;s<16;s++) {
249 printf(" %s\n", ascii);
251 printf(" %s\n%s -=> ",ascii,prefix);
255 static void ttf_table_dump(ttf_table_t*t, const char*prefix)
258 hexdump(t->data, t->len, prefix);
261 static table_head_t*head_new(ttf_t*ttf)
263 table_head_t*head = rfx_calloc(sizeof(table_head_t));
264 head->units_per_em = 1024;
266 if(ttf->num_glyphs) {
267 head->xmin = ttf->glyphs[0].xmin;
268 head->ymin = ttf->glyphs[0].ymin;
269 head->xmax = ttf->glyphs[0].xmax;
270 head->ymax = ttf->glyphs[0].ymax;
271 for(t=1;t<ttf->num_glyphs;t++) {
272 if(ttf->glyphs[t].xmin < head->xmin) head->xmin = ttf->glyphs[t].xmin;
273 if(ttf->glyphs[t].ymin < head->ymin) head->ymin = ttf->glyphs[t].ymin;
274 if(ttf->glyphs[t].xmax > head->xmax) head->xmax = ttf->glyphs[t].xmax;
275 if(ttf->glyphs[t].ymax > head->ymax) head->ymax = ttf->glyphs[t].ymax;
279 head->lowest_readable_size = 8; // not sure what font renderers actually do with this
283 static int head_parse(ttf_t*ttf, memreader_t*r)
285 ttf->head = rfx_calloc(sizeof(table_head_t));
286 U32 version = readU32(r);
287 if(version!=VERSION_1_0)
288 msg("<warning> Font HEAD has unknown version %08x", version);
289 U32 revision = readU32(r);
290 U32 checksum2 = readU32(r);
291 U32 magic = readU32(r);
292 if(magic!=0x5f0f3cf5)
293 msg("<warning> Font HEAD has unknown magic number %08x", magic);
294 ttf->head->flags = readU16(r);
295 ttf->head->units_per_em = readU16(r);
296 readU32(r);readU32(r); //created
297 readU32(r);readU32(r); //modified
298 ttf->head->xmin = readU16(r);
299 ttf->head->ymin = readU16(r);
300 ttf->head->xmax = readU16(r);
301 ttf->head->ymax = readU16(r);
302 ttf->head->macStyle = readU16(r);
303 ttf->head->lowest_readable_size = readU16(r); //in pixels
304 ttf->head->dir_hint = readS16(r);
305 int loc_index = readS16(r); //used in 'loca' table
307 msg("<warning> loca index format %d unknown", loc_index);
308 U16 glyph_data_format = readS16(r);
309 if(glyph_data_format!=0)
310 msg("<warning> Font glyph data format unknown: %04x", glyph_data_format);
311 if(r->pos < r->size) {
312 msg("<warning> Leftover bytes (%d) in HEAD tag", r->size - r->pos);
316 static void head_write(ttf_t*ttf, ttf_table_t*w, int loca_size)
318 writeU32(w, 0x10000);
319 writeU32(w, 0x10000);
320 writeU32(w, 0); //checksum
321 writeU32(w, 0x5f0f3cf5); //magic
322 writeU16(w, ttf->head->flags);
323 writeU16(w, ttf->head->units_per_em);
324 writeU32(w, 0);writeU32(w, 0); //created
325 writeU32(w, 0);writeU32(w, 0); //modified
326 writeU16(w, ttf->head->xmin);
327 writeU16(w, ttf->head->ymin);
328 writeU16(w, ttf->head->xmax);
329 writeU16(w, ttf->head->ymax);
330 writeU16(w, ttf->head->macStyle);
331 writeU16(w, ttf->head->lowest_readable_size);
332 writeS16(w, ttf->head->dir_hint);
333 writeS16(w, loca_size); //loca index size (32 bit)
334 writeS16(w, 0); //glyph data format
336 static void head_dump(ttf_t*ttf)
338 printf("head->flags: %d\n", ttf->head->flags);
339 printf("head->units_per_em: %d\n", ttf->head->units_per_em);
340 printf("head->xmin: %d\n", ttf->head->xmin);
341 printf("head->ymin: %d\n", ttf->head->ymin);
342 printf("head->xmax: %d\n", ttf->head->xmax);
343 printf("head->ymax: %d\n", ttf->head->ymax);
344 printf("head->macStyle: %d\n", ttf->head->macStyle);
345 printf("head->lowest_readable_size: %d\n", ttf->head->lowest_readable_size);
346 printf("head->dir_hint: %d\n", ttf->head->dir_hint);
348 static void head_delete(ttf_t*ttf)
356 static table_os2_t*os2_new(ttf_t*ttf)
358 table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
359 if(ttf->num_glyphs) {
362 for(t=0;t<ttf->num_glyphs;t++) {
363 average_width += (ttf->glyphs[t].advance + ttf->glyphs[t].bearing);
365 os2->xAvgCharWidth = average_width / ttf->num_glyphs;
368 /* that's what everybody seems to fill in */
369 os2->usWeightClass = 400;
370 os2->usWidthClass = 5;
373 int advance = (ttf->head->xmax - ttf->head->xmin)/2;
374 int height = (ttf->head->xmax - ttf->head->xmin);
376 /* I do believe a sane font rendering engine will actually use
377 the font advance here- the subscript/superscript position will
378 not be the same for each glyph */
379 os2->ySuperscriptXSize = os2->ySubscriptXSize = (ttf->head->xmax - ttf->head->xmin)/2;
380 os2->ySuperscriptYSize = os2->ySubscriptYSize = (ttf->head->ymax - ttf->head->ymin)/2;
381 os2->ySubscriptXOffset = advance;
382 os2->ySubscriptYOffset = 0;
383 os2->ySuperscriptXOffset = advance;
384 os2->ySuperscriptYOffset = (ttf->head->ymax - ttf->head->ymin)/2;
385 os2->yStrikeoutSize = ttf->head->units_per_em / 10;
386 os2->yStrikeoutPosition = ymid;
387 os2->usWinAscent = ttf->head->ymax;
388 os2->usWinDescent = ttf->head->ymin<0?0:ttf->head->ymin;
389 os2->sxHeight = ymid;
390 os2->sCapHeight = height*2/3;
392 os2->panose_Weight = 4;
394 /* strictly speaking we'd have to set 92/64 bits in these tables, depending on
395 what parts of the unicode table is filled. (e.g. bit 90 = tibetan). */
396 os2->ulCharRange[0] = 1;
397 os2->ulCharRange[1] = 0;
398 os2->ulCharRange[2] = 0;
399 os2->ulCharRange[3] = 0;
400 os2->ulCodePageRange1 = 1;
401 os2->ulCodePageRange2 = 0;
403 if(ttf->unicode_size) {
405 for(min=0;min<ttf->unicode_size;min++)
406 if(ttf->unicode[min]) break;
407 for(max=ttf->unicode_size-1;max>=0;max--)
408 if(ttf->unicode[max]) break;
410 os2->fsFirstCharIndex = min;
411 os2->fsLastCharIndex = max;
414 os2->sTypoAscender = ttf->ascent;
415 os2->sTypoDescender = ttf->descent;
416 os2->sTypoLineGap = ttf->lineGap;
418 os2->usDefaultChar = 0;
419 os2->usBreakChar = (ttf->unicode_size>0x20 && ttf->unicode[0x20])?0x20:0;
420 os2->usMaxContext = 0; // we don't use ligatures yet
423 static table_os2_t*os2_parse(memreader_t*r)
425 table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
426 U16 version = readU16(r);
431 if(version!=0 && version!=1 && version!=2 && version!=3)
432 msg("<warning> Unknown OS2 version: %04x", version);
433 os2->xAvgCharWidth = readS16(r);
434 os2->usWeightClass = readU16(r);
435 os2->usWidthClass = readU16(r);
437 os2->ySubscriptXSize = readU16(r);
438 os2->ySubscriptYSize = readU16(r);
439 os2->ySubscriptXOffset = readU16(r);
440 os2->ySubscriptYOffset = readU16(r);
441 os2->ySuperscriptXSize = readU16(r);
442 os2->ySuperscriptYSize = readU16(r);
443 os2->ySuperscriptXOffset = readU16(r);
444 os2->ySuperscriptYOffset = readU16(r);
445 os2->yStrikeoutSize = readU16(r);
446 os2->yStrikeoutPosition = readU16(r);
447 os2->sFamilyClass = readU16(r);
448 os2->panose_FamilyType = readU8(r);
449 os2->panose_SerifStyle = readU8(r);
450 os2->panose_Weight = readU8(r);
451 os2->panose_Proportion = readU8(r);
452 os2->panose_Contrast = readU8(r);
453 os2->panose_StrokeVariation = readU8(r);
454 os2->panose_ArmStyle = readU8(r);
455 os2->panose_Letterform = readU8(r);
456 os2->panose_Midline = readU8(r);
457 os2->panose_XHeight = readU8(r);
458 os2->ulCharRange[0] = readU32(r);
459 os2->ulCharRange[1] = readU32(r);
460 os2->ulCharRange[2] = readU32(r);
461 os2->ulCharRange[3] = readU32(r);
463 os2->fsSelection = readU16(r);
464 os2->fsFirstCharIndex = readU16(r);
465 os2->fsLastCharIndex = readU16(r);
466 os2->sTypoAscender = readS16(r);
467 os2->sTypoDescender = readS16(r);
468 os2->sTypoLineGap = readS16(r);
469 os2->usWinAscent = readU16(r);
470 os2->usWinDescent = readU16(r);
471 if(version<1) return os2;
472 os2->ulCodePageRange1 = readU32(r);
473 os2->ulCodePageRange2 = readU32(r);
474 if(version<2) return os2;
475 os2->sxHeight = readS16(r);
476 os2->sCapHeight = readS16(r);
477 os2->usDefaultChar = readU16(r);
478 os2->usBreakChar = readU16(r);
479 os2->usMaxContext = readU16(r);
481 if(r->pos < r->size) {
482 msg("<warning> Leftover bytes (%d) in OS2 tag", r->size - r->pos);
486 static void os2_write(ttf_t*ttf, ttf_table_t*w)
488 table_os2_t*os2 = ttf->os2;
490 if(os2->sxHeight|os2->sCapHeight|os2->usDefaultChar|os2->usBreakChar|os2->usMaxContext) {
493 writeU16(w, version);
494 writeS16(w, os2->xAvgCharWidth);
495 writeU16(w, os2->usWeightClass);
496 writeU16(w, os2->usWidthClass);
497 writeU16(w, 0); //fstype
498 writeU16(w, os2->ySubscriptXSize);
499 writeU16(w, os2->ySubscriptYSize);
500 writeU16(w, os2->ySubscriptXOffset);
501 writeU16(w, os2->ySubscriptYOffset);
502 writeU16(w, os2->ySuperscriptXSize);
503 writeU16(w, os2->ySuperscriptYSize);
504 writeU16(w, os2->ySuperscriptXOffset);
505 writeU16(w, os2->ySuperscriptYOffset);
506 writeU16(w, os2->yStrikeoutSize);
507 writeU16(w, os2->yStrikeoutPosition);
508 writeU16(w, os2->sFamilyClass);
509 writeU8(w, os2->panose_FamilyType);
510 writeU8(w, os2->panose_SerifStyle);
511 writeU8(w, os2->panose_Weight);
512 writeU8(w, os2->panose_Proportion);
513 writeU8(w, os2->panose_Contrast);
514 writeU8(w, os2->panose_StrokeVariation);
515 writeU8(w, os2->panose_ArmStyle);
516 writeU8(w, os2->panose_Letterform);
517 writeU8(w, os2->panose_Midline);
518 writeU8(w, os2->panose_XHeight);
519 writeU32(w, os2->ulCharRange[0]);
520 writeU32(w, os2->ulCharRange[1]);
521 writeU32(w, os2->ulCharRange[2]);
522 writeU32(w, os2->ulCharRange[3]);
523 writeU32(w, 0x53434244); //vendor
524 writeU16(w, os2->fsSelection);
525 writeU16(w, os2->fsFirstCharIndex);
526 writeU16(w, os2->fsLastCharIndex);
527 writeS16(w, os2->sTypoAscender);
528 writeS16(w, os2->sTypoDescender);
529 writeS16(w, os2->sTypoLineGap);
530 writeU16(w, os2->usWinAscent);
531 writeU16(w, os2->usWinDescent);
532 if(version<1) return;
533 writeU32(w, os2->ulCodePageRange1);
534 writeU32(w, os2->ulCodePageRange2);
535 if(version<2) return;
536 writeS16(w, os2->sxHeight);
537 writeS16(w, os2->sCapHeight);
538 writeU16(w, os2->usDefaultChar);
539 writeU16(w, os2->usBreakChar);
540 writeU16(w, os2->usMaxContext);
542 static void os2_dump(ttf_t*ttf)
544 table_os2_t*os2 = ttf->os2;
546 printf("os2->xAvgCharWidth: %d\n", os2->xAvgCharWidth);
547 printf("os2->usWeightClass: %d\n", os2->usWeightClass);
548 printf("os2->usWidthClass: %d\n", os2->usWidthClass);
549 printf("os2->ySubscriptXSize: %d\n", os2->ySubscriptXSize);
550 printf("os2->ySubscriptYSize: %d\n", os2->ySubscriptYSize);
551 printf("os2->ySubscriptXOffset: %d\n", os2->ySubscriptXOffset);
552 printf("os2->ySubscriptYOffset: %d\n", os2->ySubscriptYOffset);
553 printf("os2->ySuperscriptXSize: %d\n", os2->ySuperscriptXSize);
554 printf("os2->ySuperscriptYSize: %d\n", os2->ySuperscriptYSize);
555 printf("os2->ySuperscriptXOffset: %d\n", os2->ySuperscriptXOffset);
556 printf("os2->ySuperscriptYOffset: %d\n", os2->ySuperscriptYOffset);
557 printf("os2->yStrikeoutSize: %d\n", os2->yStrikeoutSize);
558 printf("os2->yStrikeoutPosition: %d\n", os2->yStrikeoutPosition);
559 printf("os2->sFamilyClass: %d\n", os2->sFamilyClass);
560 printf("os2->panose_FamilyType: %d\n", os2->panose_FamilyType);
561 printf("os2->panose_SerifStyle: %d\n", os2->panose_SerifStyle);
562 printf("os2->panose_Weight: %d\n", os2->panose_Weight);
563 printf("os2->panose_Proportion: %d\n", os2->panose_Proportion);
564 printf("os2->panose_Contrast: %d\n", os2->panose_Contrast);
565 printf("os2->panose_StrokeVariation: %d\n", os2->panose_StrokeVariation);
566 printf("os2->panose_ArmStyle: %d\n", os2->panose_ArmStyle);
567 printf("os2->panose_Letterform: %d\n", os2->panose_Letterform);
568 printf("os2->panose_Midline: %d\n", os2->panose_Midline);
569 printf("os2->panose_XHeight: %d\n", os2->panose_XHeight);
570 printf("os2->ulCharRange[0]: %d\n", os2->ulCharRange[0]);
571 printf("os2->ulCharRange[1]: %d\n", os2->ulCharRange[1]);
572 printf("os2->ulCharRange[2]: %d\n", os2->ulCharRange[2]);
573 printf("os2->ulCharRange[3]: %d\n", os2->ulCharRange[3]);
574 printf("os2->fsSelection: %d\n", os2->fsSelection);
575 printf("os2->fsFirstCharIndex: %d\n", os2->fsFirstCharIndex);
576 printf("os2->fsLastCharIndex: %d\n", os2->fsLastCharIndex);
577 printf("os2->sTypoAscender: %d\n", os2->sTypoAscender);
578 printf("os2->sTypoDescender: %d\n", os2->sTypoDescender);
579 printf("os2->sTypoLineGap: %d\n", os2->sTypoLineGap);
580 printf("os2->usWinAscent: %d\n", os2->usWinAscent);
581 printf("os2->usWinDescent: %d\n", os2->usWinDescent);
582 printf("os2->ulCodePageRange1: %d\n", os2->ulCodePageRange1);
583 printf("os2->ulCodePageRange2: %d\n", os2->ulCodePageRange2);
584 printf("os2->sxHeight: %d\n", os2->sxHeight);
585 printf("os2->sCapHeight: %d\n", os2->sCapHeight);
586 printf("os2->usDefaultChar: %d\n", os2->usDefaultChar);
587 printf("os2->usBreakChar: %d\n", os2->usBreakChar);
588 printf("os2->usMaxContext: %d\n", os2->usMaxContext);
590 static void os2_delete(ttf_t*ttf)
597 static table_maxp_t*maxp_new(ttf_t*ttf)
599 table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
601 if(ttf->num_glyphs) {
603 for(t=0;t<ttf->num_glyphs;t++) {
604 if(ttf->glyphs[t].num_points>max)
605 max = ttf->glyphs[t].num_points;
608 for(s=0;s<ttf->glyphs[t].num_points;s++) {
609 if(ttf->glyphs[t].points[s].flags&GLYPH_CONTOUR_END)
612 if(maxp->maxContours < contours)
613 maxp->maxContours = contours;
615 maxp->maxPoints = max;
617 /* we don't generate composite glyphs yet */
618 maxp->maxComponentPoints = 0;
619 maxp->maxComponentContours = 0;
623 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
625 U32 version = readU32(r);
626 ttf->num_glyphs = readU16(r);
627 /* according to freetype, older fonts (version<0x10000)
628 apparently only contain the number of glyphs. this is
629 rather rare, though. */
630 if(version<0x10000 && r->size==6) return 0;
633 msg("<warning> Truncated maxp table (version %d)", version);
635 table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
636 maxp->maxPoints = readU16(r);
637 maxp->maxContours = readU16(r);
638 maxp->maxComponentPoints = readU16(r);
639 maxp->maxComponentContours = readU16(r);
640 maxp->maxZones = readU16(r);
641 maxp->maxTwilightPoints = readU16(r);
642 maxp->maxStorage = readU16(r);
643 maxp->maxFunctionDefs = readU16(r);
644 maxp->maxInstructionDefs = readU16(r);
645 maxp->maxStackElements = readU16(r);
646 maxp->maxSizeOfInstructions = readU16(r);
647 maxp->maxComponentElements = readU16(r);
648 maxp->maxComponentDepth = readU16(r);
651 static void maxp_write(ttf_t*ttf, ttf_table_t*w)
653 table_maxp_t*maxp = ttf->maxp;
655 /* version 0.5 simplified maxp table */
656 writeU32(w, 0x00005000);
657 writeU16(w, ttf->num_glyphs);
660 writeU32(w, 0x10000); //version
661 writeU16(w, ttf->num_glyphs);
662 writeU16(w, maxp->maxPoints);
663 writeU16(w, maxp->maxContours);
664 writeU16(w, maxp->maxComponentPoints);
665 writeU16(w, maxp->maxComponentContours);
666 writeU16(w, maxp->maxZones);
667 writeU16(w, maxp->maxTwilightPoints);
668 writeU16(w, maxp->maxStorage);
669 writeU16(w, maxp->maxFunctionDefs);
670 writeU16(w, maxp->maxInstructionDefs);
671 writeU16(w, maxp->maxStackElements);
672 writeU16(w, maxp->maxSizeOfInstructions);
673 writeU16(w, maxp->maxComponentElements);
674 writeU16(w, maxp->maxComponentDepth);
676 static void maxp_dump(ttf_t*ttf)
678 table_maxp_t*maxp = ttf->maxp;
680 printf("maxp->maxPoints: %d\n", maxp->maxPoints);
681 printf("maxp->maxContours: %d\n", maxp->maxContours);
682 printf("maxp->maxComponentPoints: %d\n", maxp->maxComponentPoints);
683 printf("maxp->maxComponentContours: %d\n", maxp->maxComponentContours);
684 printf("maxp->maxZones: %d\n", maxp->maxZones);
685 printf("maxp->maxTwilightPoints: %d\n", maxp->maxTwilightPoints);
686 printf("maxp->maxStorage: %d\n", maxp->maxStorage);
687 printf("maxp->maxFunctionDefs: %d\n", maxp->maxFunctionDefs);
688 printf("maxp->maxInstructionDefs: %d\n", maxp->maxInstructionDefs);
689 printf("maxp->maxStackElements: %d\n", maxp->maxStackElements);
690 printf("maxp->maxSizeOfInstructions: %d\n", maxp->maxSizeOfInstructions);
691 printf("maxp->maxComponentElements: %d\n", maxp->maxComponentElements);
692 printf("maxp->maxComponentDepth: %d\n", maxp->maxComponentDepth);
694 static void maxp_delete(ttf_t*ttf)
701 static table_hea_t*hea_new(ttf_t*ttf)
703 table_hea_t*hea = rfx_calloc(sizeof(table_hea_t));
704 if(ttf->num_glyphs) {
706 for(t=0;t<ttf->num_glyphs;t++) {
707 if(ttf->glyphs[t].advance > hea->advanceWidthMax)
708 hea->advanceWidthMax = ttf->glyphs[t].advance;
709 if(ttf->glyphs[t].xmin < hea->minLeftSideBearing)
710 hea->minLeftSideBearing = ttf->glyphs[t].xmin;
711 if(ttf->glyphs[t].xmax < hea->minRightSideBearing)
712 hea->minRightSideBearing = ttf->glyphs[t].xmax;
713 int width = ttf->glyphs[t].xmax - ttf->glyphs[t].xmin;
714 if(width > hea->xMaxExtent)
715 hea->xMaxExtent = width;
721 static int hea_parse(memreader_t*r, ttf_t*ttf)
723 table_hea_t*hea = ttf->hea = rfx_calloc(sizeof(table_hea_t));
724 U32 version = readU32(r);
725 ttf->ascent = readS16(r);
726 ttf->descent = readS16(r);
727 ttf->lineGap = readS16(r);
728 hea->advanceWidthMax = readU16(r);
729 hea->minLeftSideBearing = readS16(r);
730 hea->minRightSideBearing = readS16(r);
731 hea->xMaxExtent = readS16(r);
732 hea->caretSlopeRise = readS16(r);
733 hea->caretSlopeRun = readS16(r);
734 hea->caretOffset = readS16(r);
735 readS16(r); //reserved[0]
736 readS16(r); //reserved[1]
737 readS16(r); //reserved[2]
738 readS16(r); //reserved[3]
739 S16 metricDataFormat = readS16(r); //should be 0
740 if(metricDataFormat!=0) {
741 msg("<warning> Unknown metric format %d", metricDataFormat);
743 int num_advances = readU16(r);
744 if(num_advances > ttf->num_glyphs) {
745 msg("<warning> bad number of horizontal metrics: %d", num_advances);
746 num_advances = ttf->num_glyphs;
750 static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances)
752 table_hea_t*hea = ttf->hea;
753 writeU32(w, 0x00010000);
754 writeS16(w, ttf->ascent);
755 writeS16(w, ttf->descent);
756 writeS16(w, ttf->lineGap);
757 writeU16(w, hea->advanceWidthMax);
758 writeS16(w, hea->minLeftSideBearing);
759 writeS16(w, hea->minRightSideBearing);
760 writeS16(w, hea->xMaxExtent);
761 writeS16(w, hea->caretSlopeRise);
762 writeS16(w, hea->caretSlopeRun);
763 writeS16(w, hea->caretOffset);
764 writeS16(w, 0); //reserved
765 writeS16(w, 0); //reserved
766 writeS16(w, 0); //reserved
767 writeS16(w, 0); //reserved
768 writeS16(w, 0); //metricDataFormat
769 writeU16(w, num_advances);
772 static void hea_dump(ttf_t*ttf)
774 table_hea_t*hea = ttf->hea;
776 const char*dir = ttf->is_vertical?"v":"h";
777 printf("%shea->ascent: %d\n", dir, ttf->ascent);
778 printf("%shea->descent: %d\n", dir, ttf->descent);
779 printf("%shea->lineGap: %d\n", dir, ttf->lineGap);
780 printf("%shea->advanceWidthMax: %d\n", dir, hea->advanceWidthMax);
781 printf("%shea->minLeftSideBearing: %d\n", dir, hea->minLeftSideBearing);
782 printf("%shea->minRightSideBearing: %d\n", dir, hea->minRightSideBearing);
783 printf("%shea->xMaxExtent: %d\n", dir, hea->xMaxExtent);
784 printf("%shea->caretSlopeRise: %d\n", dir, hea->caretSlopeRise);
785 printf("%shea->caretSlopeRun: %d\n", dir, hea->caretSlopeRun);
786 printf("%shea->caretOffset: %d\n", dir, hea->caretOffset);
788 static void hea_delete(ttf_t*ttf)
796 static void mtx_parse(memreader_t*r, ttf_t*ttf, int num_advances)
800 if(num_advances > r->size/4)
801 num_advances = r->size/4;
802 for(t=0;t<num_advances;t++) {
803 old_advance = ttf->glyphs[t].advance = readU16(r);
804 ttf->glyphs[t].bearing = readS16(r);
806 int rest = (r->size - num_advances*4)/2;
807 if(ttf->num_glyphs < num_advances+rest) {
808 rest = ttf->num_glyphs-num_advances;
810 for(t=0;t<rest;t++) {
811 ttf->glyphs[t].advance = old_advance;
812 ttf->glyphs[t].bearing = readS16(r);
815 static int mtx_write(ttf_t*ttf, ttf_table_t*w)
817 int num_advances = ttf->num_glyphs;
818 if(ttf->num_glyphs>=2) {
820 for(t=ttf->num_glyphs-1;t>0;t--) {
821 if(ttf->glyphs[t-1].advance !=
822 ttf->glyphs[t].advance) break;
824 /* we need to store all individual advances as well
825 as one entry for the constant */
830 for(t=0;t<num_advances;t++) {
831 writeU16(w, ttf->glyphs[t].advance);
832 writeU16(w, ttf->glyphs[t].bearing);
834 for(;t<ttf->num_glyphs;t++) {
835 writeU16(w, ttf->glyphs[t].bearing);
840 static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size)
843 int num = ttf->num_glyphs+1;
844 U32*locations = rfx_calloc(num*sizeof(U32));
847 char warn_unsorted = 1;
849 if(num*4 > r->size) {
850 msg("<warning> Short 'loca' table (32 bit): %d/%d", r->size/4, num);
853 if(num*4 < r->size) {
854 msg("<warning> Extraneous data (%d bytes) in 'loca' table (32 bit)", r->size-num*4);
857 locations[t] = loc = readU32(r);
858 if(lastloc > loc && warn_unsorted) {
859 msg("<warning> Unsorted 'loca' table (32 bit)");
865 if(num*2 > r->size) {
866 msg("<warning> Short 'loca' table (16 bit)");
869 if(num*2 < r->size) {
870 msg("<warning> Extraneous data (%d bytes) in 'loca' table (16 bit)", r->size-num*2);
873 locations[t] = loc = readU16(r)*2;
874 if(lastloc > loc && warn_unsorted) {
875 msg("<warning> Unsorted 'loca' table");
883 static int loca_write(ttf_t*ttf, ttf_table_t*w, U32*locations)
887 for(t=0;t<=ttf->num_glyphs;t++) {
888 if(locations[t]>=0x20000 || (locations[t]&1)) {
895 for(t=0;t<=ttf->num_glyphs;t++) {
896 writeU32(w, locations[t]);
900 for(t=0;t<=ttf->num_glyphs;t++) {
901 writeU16(w, locations[t]/2);
907 static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int glyphnr)
909 ttfglyph_t*glyph = &ttf->glyphs[glyphnr];
913 endpoints = malloc(sizeof(U16)*num_contours);
916 for(s=0;s<num_contours;s++) {
917 int pos = endpoints[s] = readU16(r);
919 msg("<warning> Unsorted endpoints array (len:%d) last=%d now=%d", s, pos, lastpos);
924 U16 code_len = readU16(r);
926 glyph->code = malloc(sizeof(U16)*code_len);
927 readBlock(r, glyph->code, code_len);
928 glyph->code_size = code_len;
934 /*msg("<notice> TTF Glyph %d) code_size=%d num_contours=%d glyph->num_points=%d %d/%d/%d/%d",
935 glyphnr, code_len, num_contours, glyph->num_points,
936 xmin, ymin, xmax, ymax);*/
937 INIT_READ(fx, r->mem, r->size, r->pos);
938 INIT_READ(fy, r->mem, r->size, r->pos);
940 glyph->num_points = endpoints[num_contours-1] + 1;
941 glyph->points = rfx_calloc(sizeof(ttfpoint_t)*glyph->num_points);
943 /* parse flag array (1st pass- to determine start of coordinates) */
945 while(num<glyph->num_points) {
948 msg("<error> Bad flags in glyph outline: %02x (at pos %d)", flag, num);
951 glyph->num_points = 0;
957 if(count+num>glyph->num_points) {
958 msg("<warning> Bad count (%d) in glyph (%d) (at pos %d)", count, glyphnr, num);
959 count = glyph->num_points-num;
964 /* parse flag array (2nd pass) and x coordinates */
969 int bytepos = r->pos;
970 while(num<glyph->num_points) {
971 U8 flag = readU8(&fx);
972 int count = flag&8?readU8(&fx)+1:1;
973 count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
976 if(contour_pos<num_contours && num==endpoints[contour_pos]) {
981 if((flag&0x12) == 0x12) x += readU8(r);
982 else if((flag&0x12) == 0x02) x -= readU8(r);
983 else if((flag&0x12) == 0x00) x += readS16(r);
985 glyph->points[num].x = x;
986 U8 f = flag&GLYPH_ON_CURVE;
987 if(is_start) f|=GLYPH_CONTOUR_START;
988 if(is_end) f|=GLYPH_CONTOUR_END;
989 glyph->points[num].flags = f;
995 /* parse flag array (3rd pass) and y coordinates */
998 while(num<glyph->num_points) {
999 U8 flag = readU8(&fy);
1000 int count = flag&8?readU8(&fy)+1:1;
1001 count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
1003 if((flag&0x24) == 0x24) y += readU8(r);
1004 else if((flag&0x24) == 0x04) y -= readU8(r);
1005 else if((flag&0x24) == 0x00) y += readS16(r);
1006 glyph->points[num].y = y;
1013 static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
1016 char warn_about_compound_glyphs=0;
1017 for(t=0;t<ttf->num_glyphs;t++) {
1018 INIT_READ(r, rr->mem, rr->size, loca[t]);
1019 if(loca[t]==loca[t+1] || loca[t]==r.size)
1020 continue; //empty glyph
1021 if(r.pos+10>r.size) {
1022 msg("<warning> Truncated glyph entry %d/%d (or bad loca entry %d/%d, next loca: %d)",
1023 t, ttf->num_glyphs, loca[t], r.size, loca[t+1]);
1026 S16 num_contours = readS16(&r);
1027 ttf->glyphs[t].xmin = readS16(&r);
1028 ttf->glyphs[t].ymin = readS16(&r);
1029 ttf->glyphs[t].xmax = readS16(&r);
1030 ttf->glyphs[t].ymax = readS16(&r);
1032 if(num_contours<0) {
1033 if(warn_about_compound_glyphs)
1034 msg("<error> Compound glyphs not supported yet");
1035 warn_about_compound_glyphs=0;
1037 if(!parse_simple_glyph(ttf, &r, num_contours, t))
1043 void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
1045 /* endpoints array */
1047 for(s=0;s<g->num_points;s++) {
1048 if(g->points[s].flags&GLYPH_CONTOUR_END)
1053 writeU16(w, g->code_size);
1055 writeBlock(w, g->code, g->code_size);
1062 for(s=0;s<g->num_points;s++) {
1063 ttfpoint_t*p = &g->points[s];
1064 int dx = p->x - lastx;
1065 int dy = p->y - lasty;
1066 U8 flags = p->flags&GLYPH_ON_CURVE;
1069 } else if(dx<0 && dx>=-255) {
1071 } else if(dx>0 && dx<=255) {
1076 } else if(dy<0 && dy>=-255) {
1078 } else if(dy>0 && dy<=255) {
1081 if(flags == lastflag && flagcount<255) {
1086 writeU8(w, lastflag|8);
1087 writeU8(w, flagcount);
1089 writeU8(w, lastflag);
1100 writeU8(w, lastflag|8);
1101 writeU8(w, flagcount);
1103 writeU8(w, lastflag);
1108 int bytepos = w->len;
1109 for(s=0;s<g->num_points;s++) {
1110 ttfpoint_t*p = &g->points[s];
1111 int dx = p->x - lastx;
1112 if(dx>32767 || dx<-32768) {
1113 msg("<error> Coordinate overflow in glyph");
1116 if(dx>0 && dx<=255) writeU8(w, dx);
1117 else if(dx<0 && dx>=-255) writeU8(w, -dx);
1118 else if(dx) writeS16(w, dx);
1122 for(s=0;s<g->num_points;s++) {
1123 ttfpoint_t*p = &g->points[s];
1124 int dy = p->y - lasty;
1125 if(dy>32767 || dy<-32768) {
1126 msg("<error> Coordinate overflow in glyph");
1129 if(dy>0 && dy<=255) writeU8(w, dy);
1130 else if(dy<0 && dy>=-255) writeU8(w, -dy);
1131 else if(dy) writeS16(w, dy);
1134 U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
1136 U32*locations = malloc(sizeof(U32)*(ttf->num_glyphs+1));
1138 for(t=0;t<ttf->num_glyphs;t++) {
1139 locations[t] = w->len;
1140 ttfglyph_t*g = &ttf->glyphs[t];
1142 int num_contours = 0;
1143 for(s=0;s<g->num_points;s++) {
1144 if(g->points[s].flags&GLYPH_CONTOUR_END)
1147 writeS16(w, num_contours?num_contours:1);
1148 writeS16(w, g->xmin);
1149 writeS16(w, g->ymin);
1150 writeS16(w, g->xmax);
1151 writeS16(w, g->ymax);
1154 /* some ttf parsers can't deal with zero contours, so in the case
1155 of an empty glyph, write a single point (0,0) */
1156 writeU16(w, 0); //endpoint of 1st contour
1157 writeU16(w, g->code_size);
1159 writeBlock(w, g->code, g->code_size);
1160 writeU8(w, 0x31); //flag (xy=(0,0),on curve)
1162 write_simple_glyph(w, g);
1165 locations[t] = w->len;
1168 void glyf_dump(ttf_t* ttf)
1170 if(!ttf->glyphs) return;
1172 for(t=0;t<ttf->num_glyphs;t++) {
1173 ttfglyph_t*g = &ttf->glyphs[t];
1174 printf("glyph %d)\n", t);
1175 printf(" advance=%d\n", g->advance);
1176 printf(" bearing=%d\n", g->bearing);
1177 printf(" bbox=(%d/%d/%d/%d)\n", g->xmin, g->ymin, g->xmax, g->ymax);
1178 printf(" points=(");
1180 for(s=0;s<g->num_points;s++) {
1182 printf("%d/%d/0x%02x", g->points[s].x, g->points[s].y, g->points[s].flags);
1186 hexdump(g->code, g->code_size, " ");
1189 void glyf_delete(ttf_t* ttf)
1194 for(t=0;t<ttf->num_glyphs;t++) {
1195 if(ttf->glyphs[t].code) {
1196 free(ttf->glyphs[t].code);
1197 ttf->glyphs[t].code = 0;
1199 if(ttf->glyphs[t].points) {
1200 free(ttf->glyphs[t].points);
1201 ttf->glyphs[t].points = 0;
1204 free(ttf->glyphs);ttf->glyphs=0;
1207 static void grow_unicode(ttf_t*ttf, int index)
1211 ttf->unicode = rfx_calloc(sizeof(ttf->unicode[0])*size);
1212 } else if(ttf->unicode_size<size) {
1213 ttf->unicode = rfx_realloc(ttf->unicode, sizeof(ttf->unicode[0])*size);
1214 memset(ttf->unicode+ttf->unicode_size, 0, sizeof(ttf->unicode[0])*(size - ttf->unicode_size));
1216 ttf->unicode_size = size;
1218 void cmap_parse(memreader_t*r, ttf_t*ttf)
1220 readU16(r); // version (0)
1221 int num_subtables = readU16(r);
1223 if(r->pos+num_subtables*8 > r->size) {
1224 msg("<warning> CMap overflow");
1225 num_subtables = (r->size-r->pos)/8;
1228 for(t=0;t<num_subtables;t++) {
1229 U16 platform = readU16(r);
1230 U16 encoding = readU16(r);
1231 U32 offset = readU32(r);
1232 if(offset>r->size) {
1233 msg("<warning> CMAP table %d %d is out of bounds (%d)", platform, encoding, offset);
1237 int is_unicode = platform==0 ||
1238 platform==3 && encoding == 1 ||
1239 platform==3 && encoding == 10;
1244 INIT_READ(t, r->mem, r->size, offset);
1245 U16 format = readU16(&t);
1246 int length = readU16(&t);
1247 U16 language = readU16(&t);
1250 msg("<warning> Language code %02x in unicode mapping", language);
1255 if(t.pos+length > t.size) {
1256 msg("<warning> overflow in format 0 cmap table");
1259 data = malloc(num*sizeof(unicode_t));
1261 grow_unicode(ttf, num);
1262 for(s=0;s<num;s++) {
1263 ttf->unicode[s] = readU8(&t);
1265 } else if(format == 4) {
1266 U16 segment_count = readU16(&t);
1267 if(segment_count&1) {
1268 msg("<error> Bad segmentx2 count %d", segment_count);
1272 readU16(&t); //searchrange
1273 readU16(&t); //entry selector
1274 readU16(&t); //range shift
1275 INIT_READ(r_end, t.mem, t.size, t.pos);
1276 INIT_READ(r_start, t.mem, t.size, t.pos+2+segment_count*2);
1277 INIT_READ(r_delta, t.mem, t.size, t.pos+2+segment_count*4);
1278 INIT_READ(r_range, t.mem, t.size, t.pos+2+segment_count*6);
1279 int glyphmap_start = t.pos+2+segment_count*8;
1281 for(s=0;s<segment_count;s++) {
1282 U16 start = readU16(&r_start);
1283 U16 end = readU16(&r_end);
1284 U16 delta = readU16(&r_delta);
1285 U16 range = readU16(&r_range);
1286 if(start==0xffff && end==0xffff && delta==1) {
1287 /* this is a common (maybe even required) occurence in fonts
1288 which explicitly map "unicode undefined" (0xffff) to
1289 "glyph undefined" (0).
1290 We don't want to blow our unicode table up to 65536 just
1291 because of this, so ignore this entry.
1295 grow_unicode(ttf, end);
1298 for(u=start;u<=end;u++) {
1299 ttf->unicode[u] = (u + delta) & 0xffff;
1302 INIT_READ(g, t.mem, t.size, r_range.pos-2+range);
1303 for(u=start;u<=end;u++) {
1304 ttf->unicode[u] = readU16(&g);
1311 static int segment_size(unicode_t*unicode, int pos, int size)
1315 for(s=pos;s<size;s++) {
1319 /* a segment costs us 8 bytes, so for more than 4 consecutive
1320 zero entries (16 bit each) in the glyph index array,
1321 it pays off to start a new segment */
1325 s -= count; // go to the last filled in entry
1330 void cmap_write(ttf_t* ttf, ttf_table_t*w)
1332 writeU16(w, 0); //version
1333 writeU16(w, 2); //two tables
1335 writeU16(w, 0); //platform (unicode)
1336 writeU16(w, 3); //encoding (unicode 2.0)
1337 writeU32(w, 20); //offset
1339 writeU16(w, 3); //platform (windows)
1340 writeU16(w, 1); //encoding (unicode basic multilingual plane UCS-2)
1341 writeU32(w, 20); //offset
1343 writeU16(w, 4); // format=4
1344 int length_pos = w->len;
1345 writeU16(w, 0); // length: we don't know yet
1346 writeU16(w, 0); // language (n/a for unicode)
1347 int num_segments_pos = w->len;
1348 writeU16(w, 0); //number of segments: we don't know yet either
1349 writeU16(w, 0); //searchrange
1350 writeU16(w, 0); //entry selector
1351 writeU16(w, 0); //range shift
1355 while(pos < ttf->unicode_size) {
1356 if(!ttf->unicode[pos]) {
1360 int s = segment_size(ttf->unicode, pos, ttf->unicode_size);
1365 num_segments++; // account for 0xffff mapping
1368 int end_pos = w->len;
1369 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
1370 writeU16(w, 0); //reserved byte
1371 int start_pos = w->len;
1372 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //start array
1373 int delta_pos = w->len;
1374 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //delta array
1375 int range_pos = w->len;
1376 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //range array
1378 w->data[num_segments_pos]=(num_segments*2)>>8;
1379 w->data[num_segments_pos+1]=(num_segments*2);
1383 while(pos < ttf->unicode_size) {
1384 if(!ttf->unicode[pos]) {
1388 U16 end = segment_size(ttf->unicode, pos, ttf->unicode_size);
1389 w->data[end_pos++]=end>>8;
1390 w->data[end_pos++]=end;
1391 w->data[start_pos++]=pos>>8;
1392 w->data[start_pos++]=pos;
1394 U16 delta = ttf->unicode[pos]-pos;
1396 for(s=pos+1;s<=end;s++) {
1397 U16 delta2 = ttf->unicode[pos]-pos;
1408 range = w->len - range_pos+num_segments*2;
1409 for(s=pos;s<=end;s++) {
1410 writeU16(w, ttf->unicode[s]);
1413 w->data[delta_pos++]=delta>>8;
1414 w->data[delta_pos++]=delta;
1415 w->data[range_pos++]=range>>8;
1416 w->data[range_pos++]=range;
1421 /* write out a mapping from 0xffff to 0- seems to be required
1422 by some libraries (e.g. fonttools) */
1423 w->data[end_pos++]=0xff;
1424 w->data[end_pos++]=0xff;
1425 w->data[start_pos++]=0xff;
1426 w->data[start_pos++]=0xff;
1427 w->data[delta_pos++]=0;
1428 w->data[delta_pos++]=1;
1429 w->data[range_pos++]=0;
1430 w->data[range_pos++]=0;
1432 w->data[length_pos]=(w->len-20)>>8;
1433 w->data[length_pos+1]=w->len-20;
1435 void cmap_delete(ttf_t*ttf)
1441 ttf->unicode_size=0;
1443 void name_parse(memreader_t*r, ttf_t*ttf)
1445 U16 format = readU16(r);
1446 U16 count = readU16(r);
1447 U16 offset = readU16(r);
1450 for(t=0;t<count;t++) {
1451 U16 platform = readU16(r);
1452 U16 encoding = readU16(r);
1453 U16 language = readU16(r);
1454 U16 name_id = readU16(r);
1455 U16 len = readU16(r);
1456 U16 offset_2 = readU16(r);
1460 ttf->name = strdup_n(&r->mem[offset+offset_2], len);
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 table_post_t*post_new(ttf_t*ttf)
1491 table_post_t*post = rfx_calloc(sizeof(table_post_t));
1494 void post_parse(memreader_t*r, ttf_t*ttf)
1496 table_post_t*post = ttf->post = rfx_calloc(sizeof(table_post_t));
1497 U16 format = readU16(r);
1498 post->italic_angle = readU16(r);
1499 post->underline_position = readU16(r);
1500 post->underline_thickness = readU16(r);
1501 U16 is_monospaced = readU16(r);
1502 readU16(r); // min mem 42
1504 readU16(r); // min mem 1
1507 void post_write(ttf_t*ttf, ttf_table_t*table)
1509 table_post_t*post = ttf->post;
1510 writeU32(table, 0x00030000);
1511 writeU32(table, post->italic_angle);
1512 writeU16(table, post->underline_position);
1513 writeU16(table, post->underline_thickness);
1514 writeU32(table, 0); //is monospaced TODO
1515 writeU32(table, 0); //min mem 42
1517 writeU32(table, 0); //min mem 1
1520 void post_delete(ttf_t*ttf)
1526 static int ttf_parse_tables(ttf_t*ttf)
1530 table = ttf_find_table(ttf, TAG_HEAD);
1532 msg("<error> Font has no head table");
1535 INIT_READ(m, table->data, table->len, 0);
1536 int loc_index = head_parse(ttf, &m);
1537 ttf_table_delete(ttf, table);
1539 table = ttf_find_table(ttf, TAG_MAXP);
1541 msg("<error> Font has no maxp table");
1544 INIT_READ(m2, table->data, table->len, 0);
1545 ttf->maxp = maxp_parse(ttf, &m2);
1546 ttf_table_delete(ttf, table);
1548 if(!ttf->num_glyphs) {
1549 msg("<error> Invalid number of characters");
1552 ttf->glyphs = rfx_calloc(sizeof(ttfglyph_t)*ttf->num_glyphs);
1554 table = ttf_find_table(ttf, TAG_OS2);
1556 INIT_READ(m, table->data, table->len, 0);
1557 ttf->os2 = os2_parse(&m);
1558 ttf_table_delete(ttf, table);
1561 table = ttf_find_table(ttf, TAG_HHEA);
1563 INIT_READ(m, table->data, table->len, 0);
1564 int num_advances = hea_parse(&m, ttf);
1565 ttf_table_delete(ttf, table);
1567 table = ttf_find_table(ttf, TAG_HMTX);
1569 INIT_READ(m, table->data, table->len, 0);
1570 mtx_parse(&m, ttf, num_advances);
1571 ttf_table_delete(ttf, table);
1574 table = ttf_find_table(ttf, TAG_VHEA);
1577 INIT_READ(m, table->data, table->len, 0);
1578 int num_advances = hea_parse(&m, ttf);
1579 ttf_table_delete(ttf, table);
1581 table = ttf_find_table(ttf, TAG_VMTX);
1583 INIT_READ(m, table->data, table->len, 0);
1584 mtx_parse(&m, ttf, num_advances);
1585 ttf_table_delete(ttf, table);
1588 msg("<error> Font contains neither HHEA nor VHEA");
1591 table = ttf_find_table(ttf, TAG_LOCA);
1593 INIT_READ(m, table->data, table->len, 0);
1594 U32*loca = loca_parse(&m, ttf, loc_index);
1595 ttf_table_delete(ttf, table);
1596 table = ttf_find_table(ttf, TAG_GLYF);
1598 INIT_READ(m, table->data, table->len, 0);
1599 glyf_parse(&m, ttf, loca);
1600 ttf_table_delete(ttf, table);
1605 table = ttf_find_table(ttf, TAG_CMAP);
1607 INIT_READ(m, table->data, table->len, 0);
1608 cmap_parse(&m, ttf);
1609 ttf_table_delete(ttf, table);
1612 table = ttf_find_table(ttf, TAG_NAME);
1614 INIT_READ(m, table->data, table->len, 0);
1615 name_parse(&m, ttf);
1616 ttf_table_delete(ttf, table);
1619 table = ttf_find_table(ttf, TAG_POST);
1621 INIT_READ(m, table->data, table->len, 0);
1622 post_parse(&m, ttf);
1623 ttf_table_delete(ttf, table);
1628 static void ttf_collapse_tables(ttf_t*ttf)
1632 table = ttf_addtable(ttf, TAG_MAXP);
1633 maxp_write(ttf, table);
1636 table = ttf_addtable(ttf, TAG_OS2);
1637 os2_write(ttf, table);
1640 if(!ttf->is_vertical) {
1641 table = ttf_addtable(ttf, TAG_HMTX);
1642 int num_advances = mtx_write(ttf, table);
1643 table = ttf_addtable(ttf, TAG_HHEA);
1644 hea_write(ttf, table, num_advances);
1646 table = ttf_addtable(ttf, TAG_VMTX);
1647 int num_advances = mtx_write(ttf, table);
1648 table = ttf_addtable(ttf, TAG_VHEA);
1649 hea_write(ttf, table, num_advances);
1653 if(ttf->num_glyphs) {
1654 table = ttf_addtable(ttf, TAG_CMAP);
1655 cmap_write(ttf, table);
1658 table = ttf_addtable(ttf, TAG_GLYF);
1659 U32*locations = glyf_write(ttf, table);
1662 table = ttf_addtable(ttf, TAG_LOCA);
1663 loca_size = loca_write(ttf, table, locations);
1668 table = ttf_addtable(ttf, TAG_NAME);
1669 name_write(ttf, table);
1673 table = ttf_addtable(ttf, TAG_POST);
1674 post_write(ttf, table);
1678 table = ttf_addtable(ttf, TAG_HEAD);
1679 head_write(ttf, table, loca_size);
1685 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1686 ttf->version = VERSION_1_0;
1689 ttf_t* ttf_load(void*data, int length)
1691 INIT_READ(r,data,length, 0);
1694 msg("<error> Truncated Truetype file (%d bytes)", length);
1698 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1699 ttf->version = readU32(&r);
1700 if(ttf->version == TTCFTAG) {
1701 /* a ttc collection is a number of truetype fonts
1702 packaged together */
1704 msg("<error> Truncated TTC file (%d bytes)", length);
1707 U32 ttcf_version = readU32(&r); // 0x00000100: v1.0, 0x00000200: v2.0, includes DSIG table
1708 U32 num_fonts = readU32(&r); // number of fonts
1709 U32 font1_position = readU32(&r);
1710 if(font1_position+12 > length) {\
1711 msg("<error> Truncated TTC file (%d bytes, first font at %d)", length, font1_position);
1714 r.pos = font1_position;
1715 ttf->version = readU32(&r);
1718 int num_tables = readU16(&r);
1720 readU16(&r); //search range
1721 readU16(&r); //entry selector
1722 readU16(&r); //range shift
1724 if(num_tables*16 > length) {
1725 msg("<error> Truncated TTC file (table entries: %d)", num_tables);
1726 if(ttf->version != OPENTYPE &&
1727 ttf->version != TRUETYPE_MACOS &&
1728 ttf->version != VERSION_1_0) {
1729 // bad table length, weird version. This is probably not a ttf file.
1734 U32*table_data = malloc(16*num_tables);
1736 for(t=0;t<num_tables*4;t++) {
1737 table_data[t] = readU32(&r);
1739 for(t=0;t<num_tables;t++) {
1740 U32 tag = table_data[t*4];
1741 U32 checksum = table_data[t*4+1];
1742 U32 pos = table_data[t*4+2];
1743 U32 len = table_data[t*4+3];
1745 if(pos+len > length) {
1746 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);
1748 U8*mem = malloc(len);
1750 readBlock(&r, mem, len);
1752 ttf_table_t*table = ttf_addtable(ttf, tag);
1754 table->len = table->memsize = len;
1756 U32 checksum2 = ttf_table_checksum(table);
1757 if(checksum2!=checksum) {
1758 msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x",
1759 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1760 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1761 len, checksum2, checksum);
1768 if(!ttf_parse_tables(ttf))
1773 void ttf_create_truetype_tables(ttf_t*ttf)
1776 ttf->head = head_new(ttf);
1778 ttf->maxp = maxp_new(ttf);
1780 ttf->hea = hea_new(ttf);
1782 ttf->os2 = os2_new(ttf);
1784 ttf->post = post_new(ttf);
1786 ttf_table_t* ttf_write(ttf_t*ttf)
1788 ttf_collapse_tables(ttf);
1790 ttf_table_t*file = ttf_table_new(0);
1791 writeU32(file, VERSION_1_0);
1793 /* write number of tables */
1795 ttf_table_t*t = ttf->tables;
1800 writeU16(file, num_tables);
1802 /* write search range */
1803 int tmp = num_tables;
1804 int search_range = 0;
1811 writeU16(file, search_range);
1813 /* write entry selector */
1814 int entry_selector = 0;
1819 writeU16(file, entry_selector);
1821 /* write range shift */
1822 int range_shift = num_tables*16 - search_range;
1823 writeU16(file, range_shift);
1825 /* write table dictionary */
1826 int table_dictionary_pos = file->len;
1827 int data_pos = file->len + num_tables*16;
1828 for(t=ttf->tables;t;t=t->next) {
1829 writeU32(file, t->id);
1830 writeU32(file, ttf_table_checksum(t));
1831 writeU32(file, data_pos);
1832 writeU32(file, t->len);
1834 data_pos += (-t->len)&3; //pad
1839 U8 zero[4]={0,0,0,0};
1840 for(t=ttf->tables;t;t=t->next) {
1841 if(t->id == TAG_HEAD)
1842 head_pos = file->len;
1843 writeBlock(file, t->data, t->len);
1844 writeBlock(file, zero, (-t->len)&3); //pad
1846 U32 checksum = 0xb1b0afba - ttf_table_checksum(file);
1847 U8*checksum2 = file->data + head_pos + 8;
1848 checksum2[0] = checksum>>24;
1849 checksum2[1] = checksum>>16;
1850 checksum2[2] = checksum>>8;
1851 checksum2[3] = checksum>>0;
1854 void ttf_save(ttf_t*ttf, const char*filename)
1856 ttf_table_t* t = ttf_write(ttf);
1857 FILE*fi = fopen(filename, "wb");
1862 fwrite(t->data, t->len, 1, fi);
1864 ttf_table_delete(0, t);
1866 void ttf_dump(ttf_t*ttf)
1868 msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
1869 ttf_table_t*table = ttf->tables;
1871 U32 tag = table->id;
1872 msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)",
1873 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1874 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
1875 table = table->next;
1877 //ttf_table_dump(ttf_find_table(ttf, TAG_MAXP));
1885 void ttf_destroy_tables(ttf_t*ttf)
1887 ttf_table_t*table = ttf->tables;
1889 ttf_table_t*next = table->next;
1896 void ttf_reduce(ttf_t*ttf)
1898 ttf_destroy_tables(ttf);
1900 void ttf_destroy(ttf_t*ttf)
1902 ttf_destroy_tables(ttf);
1913 int main(int argn, const char*argv[])
1915 setConsoleLogging(7);
1916 const char*filename = "comic.ttf";
1919 //msg("<notice> Loading %s", filename);
1920 memfile_t*m = memfile_open(filename);
1921 ttf_t*ttf = ttf_load(m->data, m->len);
1923 ttf->name = strdup("testfont");
1927 //printf("os2 version: %04x (%d), maxp size: %d\n",
1928 // ttf->os2->version, ttf->os2->size, ttf->maxp->size);
1929 ttf_save(ttf, "testfont.ttf");