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));
602 if(ttf->num_glyphs) {
604 for(t=0;t<ttf->num_glyphs;t++) {
605 if(ttf->glyphs[t].num_points>max)
606 max = ttf->glyphs[t].num_points;
609 for(s=0;s<ttf->glyphs[t].num_points;s++) {
610 if(ttf->glyphs[t].points[s].flags&GLYPH_CONTOUR_END)
613 if(maxp->maxContours < contours)
614 maxp->maxContours = contours;
616 maxp->maxPoints = max;
618 /* we don't generate composite glyphs yet */
619 maxp->maxComponentPoints = 0;
620 maxp->maxComponentContours = 0;
624 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
626 U32 version = readU32(r);
627 ttf->num_glyphs = readU16(r);
628 /* according to freetype, older fonts (version<0x10000)
629 apparently only contain the number of glyphs. this is
630 rather rare, though. */
631 if(version<0x10000 && r->size==6) return 0;
634 msg("<warning> Truncated maxp table (version %d)", version);
636 table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
637 maxp->maxPoints = readU16(r);
638 maxp->maxContours = readU16(r);
639 maxp->maxComponentPoints = readU16(r);
640 maxp->maxComponentContours = readU16(r);
641 maxp->maxZones = readU16(r);
642 maxp->maxTwilightPoints = readU16(r);
643 maxp->maxStorage = readU16(r);
644 maxp->maxFunctionDefs = readU16(r);
645 maxp->maxInstructionDefs = readU16(r);
646 maxp->maxStackElements = readU16(r);
647 maxp->maxSizeOfInstructions = readU16(r);
648 maxp->maxComponentElements = readU16(r);
649 maxp->maxComponentDepth = readU16(r);
652 static void maxp_write(ttf_t*ttf, ttf_table_t*w)
654 table_maxp_t*maxp = ttf->maxp;
656 /* version 0.5 simplified maxp table */
657 writeU32(w, 0x00005000);
658 writeU16(w, ttf->num_glyphs);
661 writeU32(w, 0x10000); //version
662 writeU16(w, ttf->num_glyphs);
663 writeU16(w, maxp->maxPoints);
664 writeU16(w, maxp->maxContours);
665 writeU16(w, maxp->maxComponentPoints);
666 writeU16(w, maxp->maxComponentContours);
667 writeU16(w, maxp->maxZones);
668 writeU16(w, maxp->maxTwilightPoints);
669 writeU16(w, maxp->maxStorage);
670 writeU16(w, maxp->maxFunctionDefs);
671 writeU16(w, maxp->maxInstructionDefs);
672 writeU16(w, maxp->maxStackElements);
673 writeU16(w, maxp->maxSizeOfInstructions);
674 writeU16(w, maxp->maxComponentElements);
675 writeU16(w, maxp->maxComponentDepth);
677 static void maxp_dump(ttf_t*ttf)
679 table_maxp_t*maxp = ttf->maxp;
681 printf("maxp->maxPoints: %d\n", maxp->maxPoints);
682 printf("maxp->maxContours: %d\n", maxp->maxContours);
683 printf("maxp->maxComponentPoints: %d\n", maxp->maxComponentPoints);
684 printf("maxp->maxComponentContours: %d\n", maxp->maxComponentContours);
685 printf("maxp->maxZones: %d\n", maxp->maxZones);
686 printf("maxp->maxTwilightPoints: %d\n", maxp->maxTwilightPoints);
687 printf("maxp->maxStorage: %d\n", maxp->maxStorage);
688 printf("maxp->maxFunctionDefs: %d\n", maxp->maxFunctionDefs);
689 printf("maxp->maxInstructionDefs: %d\n", maxp->maxInstructionDefs);
690 printf("maxp->maxStackElements: %d\n", maxp->maxStackElements);
691 printf("maxp->maxSizeOfInstructions: %d\n", maxp->maxSizeOfInstructions);
692 printf("maxp->maxComponentElements: %d\n", maxp->maxComponentElements);
693 printf("maxp->maxComponentDepth: %d\n", maxp->maxComponentDepth);
695 static void maxp_delete(ttf_t*ttf)
702 static table_hea_t*hea_new(ttf_t*ttf)
704 table_hea_t*hea = rfx_calloc(sizeof(table_hea_t));
705 if(ttf->num_glyphs) {
707 for(t=0;t<ttf->num_glyphs;t++) {
708 if(ttf->glyphs[t].advance > hea->advanceWidthMax)
709 hea->advanceWidthMax = ttf->glyphs[t].advance;
710 if(ttf->glyphs[t].xmin < hea->minLeftSideBearing)
711 hea->minLeftSideBearing = ttf->glyphs[t].xmin;
712 if(ttf->glyphs[t].xmax < hea->minRightSideBearing)
713 hea->minRightSideBearing = ttf->glyphs[t].xmax;
714 int width = ttf->glyphs[t].xmax - ttf->glyphs[t].xmin;
715 if(width > hea->xMaxExtent)
716 hea->xMaxExtent = width;
722 static int hea_parse(memreader_t*r, ttf_t*ttf)
724 table_hea_t*hea = ttf->hea = rfx_calloc(sizeof(table_hea_t));
725 U32 version = readU32(r);
726 ttf->ascent = readS16(r);
727 ttf->descent = readS16(r);
728 ttf->lineGap = readS16(r);
729 hea->advanceWidthMax = readU16(r);
730 hea->minLeftSideBearing = readS16(r);
731 hea->minRightSideBearing = readS16(r);
732 hea->xMaxExtent = readS16(r);
733 hea->caretSlopeRise = readS16(r);
734 hea->caretSlopeRun = readS16(r);
735 hea->caretOffset = readS16(r);
736 readS16(r); //reserved[0]
737 readS16(r); //reserved[1]
738 readS16(r); //reserved[2]
739 readS16(r); //reserved[3]
740 S16 metricDataFormat = readS16(r); //should be 0
741 if(metricDataFormat!=0) {
742 msg("<warning> Unknown metric format %d", metricDataFormat);
744 int num_advances = readU16(r);
745 if(num_advances > ttf->num_glyphs) {
746 msg("<warning> bad number of horizontal metrics: %d", num_advances);
747 num_advances = ttf->num_glyphs;
751 static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances)
753 table_hea_t*hea = ttf->hea;
754 writeU32(w, 0x00010000);
755 writeS16(w, ttf->ascent);
756 writeS16(w, ttf->descent);
757 writeS16(w, ttf->lineGap);
758 writeU16(w, hea->advanceWidthMax);
759 writeS16(w, hea->minLeftSideBearing);
760 writeS16(w, hea->minRightSideBearing);
761 writeS16(w, hea->xMaxExtent);
762 writeS16(w, hea->caretSlopeRise);
763 writeS16(w, hea->caretSlopeRun);
764 writeS16(w, hea->caretOffset);
765 writeS16(w, 0); //reserved
766 writeS16(w, 0); //reserved
767 writeS16(w, 0); //reserved
768 writeS16(w, 0); //reserved
769 writeS16(w, 0); //metricDataFormat
770 writeU16(w, num_advances);
773 static void hea_dump(ttf_t*ttf)
775 table_hea_t*hea = ttf->hea;
777 const char*dir = ttf->is_vertical?"v":"h";
778 printf("%shea->ascent: %d\n", dir, ttf->ascent);
779 printf("%shea->descent: %d\n", dir, ttf->descent);
780 printf("%shea->lineGap: %d\n", dir, ttf->lineGap);
781 printf("%shea->advanceWidthMax: %d\n", dir, hea->advanceWidthMax);
782 printf("%shea->minLeftSideBearing: %d\n", dir, hea->minLeftSideBearing);
783 printf("%shea->minRightSideBearing: %d\n", dir, hea->minRightSideBearing);
784 printf("%shea->xMaxExtent: %d\n", dir, hea->xMaxExtent);
785 printf("%shea->caretSlopeRise: %d\n", dir, hea->caretSlopeRise);
786 printf("%shea->caretSlopeRun: %d\n", dir, hea->caretSlopeRun);
787 printf("%shea->caretOffset: %d\n", dir, hea->caretOffset);
789 static void hea_delete(ttf_t*ttf)
797 static void mtx_parse(memreader_t*r, ttf_t*ttf, int num_advances)
801 if(num_advances > r->size/4)
802 num_advances = r->size/4;
803 for(t=0;t<num_advances;t++) {
804 old_advance = ttf->glyphs[t].advance = readU16(r);
805 ttf->glyphs[t].bearing = readS16(r);
807 int rest = (r->size - num_advances*4)/2;
808 if(ttf->num_glyphs < num_advances+rest) {
809 rest = ttf->num_glyphs-num_advances;
811 for(t=0;t<rest;t++) {
812 ttf->glyphs[t].advance = old_advance;
813 ttf->glyphs[t].bearing = readS16(r);
816 static int mtx_write(ttf_t*ttf, ttf_table_t*w)
818 int num_advances = ttf->num_glyphs;
819 if(ttf->num_glyphs>=2) {
821 for(t=ttf->num_glyphs-1;t>0;t--) {
822 if(ttf->glyphs[t-1].advance !=
823 ttf->glyphs[t].advance) break;
825 /* we need to store all individual advances as well
826 as one entry for the constant */
831 for(t=0;t<num_advances;t++) {
832 writeU16(w, ttf->glyphs[t].advance);
833 writeU16(w, ttf->glyphs[t].bearing);
835 for(;t<ttf->num_glyphs;t++) {
836 writeU16(w, ttf->glyphs[t].bearing);
841 static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size)
844 int num = ttf->num_glyphs+1;
845 U32*locations = rfx_calloc(num*sizeof(U32));
848 char warn_unsorted = 1;
850 if(num*4 > r->size) {
851 msg("<warning> Short 'loca' table (32 bit): %d/%d", r->size/4, num);
854 if(num*4 < r->size) {
855 msg("<warning> Extraneous data (%d bytes) in 'loca' table (32 bit)", r->size-num*4);
858 locations[t] = loc = readU32(r);
859 if(lastloc > loc && warn_unsorted) {
860 msg("<warning> Unsorted 'loca' table (32 bit)");
866 if(num*2 > r->size) {
867 msg("<warning> Short 'loca' table (16 bit)");
870 if(num*2 < r->size) {
871 msg("<warning> Extraneous data (%d bytes) in 'loca' table (16 bit)", r->size-num*2);
874 locations[t] = loc = readU16(r)*2;
875 if(lastloc > loc && warn_unsorted) {
876 msg("<warning> Unsorted 'loca' table");
884 static int loca_write(ttf_t*ttf, ttf_table_t*w, U32*locations)
888 for(t=0;t<=ttf->num_glyphs;t++) {
889 if(locations[t]>=0x20000 || (locations[t]&1)) {
896 for(t=0;t<=ttf->num_glyphs;t++) {
897 writeU32(w, locations[t]);
901 for(t=0;t<=ttf->num_glyphs;t++) {
902 writeU16(w, locations[t]/2);
908 static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int glyphnr)
910 ttfglyph_t*glyph = &ttf->glyphs[glyphnr];
914 endpoints = malloc(sizeof(U16)*num_contours);
917 for(s=0;s<num_contours;s++) {
918 int pos = endpoints[s] = readU16(r);
920 msg("<warning> Unsorted endpoints array (len:%d) last=%d now=%d", s, pos, lastpos);
925 U16 code_len = readU16(r);
927 glyph->code = malloc(sizeof(U16)*code_len);
928 readBlock(r, glyph->code, code_len);
929 glyph->code_size = code_len;
935 /*msg("<notice> TTF Glyph %d) code_size=%d num_contours=%d glyph->num_points=%d %d/%d/%d/%d",
936 glyphnr, code_len, num_contours, glyph->num_points,
937 xmin, ymin, xmax, ymax);*/
938 INIT_READ(fx, r->mem, r->size, r->pos);
939 INIT_READ(fy, r->mem, r->size, r->pos);
941 glyph->num_points = endpoints[num_contours-1] + 1;
942 glyph->points = rfx_calloc(sizeof(ttfpoint_t)*glyph->num_points);
944 /* parse flag array (1st pass- to determine start of coordinates) */
946 while(num<glyph->num_points) {
949 msg("<error> Bad flags in glyph outline: %02x (at pos %d)", flag, num);
952 glyph->num_points = 0;
958 if(count+num>glyph->num_points) {
959 msg("<warning> Bad count (%d) in glyph (%d) (at pos %d)", count, glyphnr, num);
960 count = glyph->num_points-num;
965 /* parse flag array (2nd pass) and x coordinates */
970 int bytepos = r->pos;
971 while(num<glyph->num_points) {
972 U8 flag = readU8(&fx);
973 int count = flag&8?readU8(&fx)+1:1;
974 count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
977 if(contour_pos<num_contours && num==endpoints[contour_pos]) {
982 if((flag&0x12) == 0x12) x += readU8(r);
983 else if((flag&0x12) == 0x02) x -= readU8(r);
984 else if((flag&0x12) == 0x00) x += readS16(r);
986 glyph->points[num].x = x;
987 U8 f = flag&GLYPH_ON_CURVE;
988 if(is_start) f|=GLYPH_CONTOUR_START;
989 if(is_end) f|=GLYPH_CONTOUR_END;
990 glyph->points[num].flags = f;
996 /* parse flag array (3rd pass) and y coordinates */
999 while(num<glyph->num_points) {
1000 U8 flag = readU8(&fy);
1001 int count = flag&8?readU8(&fy)+1:1;
1002 count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
1004 if((flag&0x24) == 0x24) y += readU8(r);
1005 else if((flag&0x24) == 0x04) y -= readU8(r);
1006 else if((flag&0x24) == 0x00) y += readS16(r);
1007 glyph->points[num].y = y;
1014 static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
1017 char warn_about_compound_glyphs=0;
1018 for(t=0;t<ttf->num_glyphs;t++) {
1019 INIT_READ(r, rr->mem, rr->size, loca[t]);
1020 if(loca[t]==loca[t+1] || loca[t]==r.size)
1021 continue; //empty glyph
1022 if(r.pos+10>r.size) {
1023 msg("<warning> Truncated glyph entry %d/%d (or bad loca entry %d/%d, next loca: %d)",
1024 t, ttf->num_glyphs, loca[t], r.size, loca[t+1]);
1027 S16 num_contours = readS16(&r);
1028 ttf->glyphs[t].xmin = readS16(&r);
1029 ttf->glyphs[t].ymin = readS16(&r);
1030 ttf->glyphs[t].xmax = readS16(&r);
1031 ttf->glyphs[t].ymax = readS16(&r);
1033 if(num_contours<0) {
1034 if(warn_about_compound_glyphs)
1035 msg("<error> Compound glyphs not supported yet");
1036 warn_about_compound_glyphs=0;
1038 if(!parse_simple_glyph(ttf, &r, num_contours, t))
1044 void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
1046 /* endpoints array */
1048 for(s=0;s<g->num_points;s++) {
1049 if(g->points[s].flags&GLYPH_CONTOUR_END)
1054 writeU16(w, g->code_size);
1056 writeBlock(w, g->code, g->code_size);
1063 for(s=0;s<g->num_points;s++) {
1064 ttfpoint_t*p = &g->points[s];
1065 int dx = p->x - lastx;
1066 int dy = p->y - lasty;
1067 U8 flags = p->flags&GLYPH_ON_CURVE;
1070 } else if(dx<0 && dx>=-255) {
1072 } else if(dx>0 && dx<=255) {
1077 } else if(dy<0 && dy>=-255) {
1079 } else if(dy>0 && dy<=255) {
1082 if(flags == lastflag && flagcount<255) {
1087 writeU8(w, lastflag|8);
1088 writeU8(w, flagcount);
1090 writeU8(w, lastflag);
1101 writeU8(w, lastflag|8);
1102 writeU8(w, flagcount);
1104 writeU8(w, lastflag);
1109 int bytepos = w->len;
1110 for(s=0;s<g->num_points;s++) {
1111 ttfpoint_t*p = &g->points[s];
1112 int dx = p->x - lastx;
1113 if(dx>32767 || dx<-32768) {
1114 msg("<error> Coordinate overflow in glyph");
1117 if(dx>0 && dx<=255) writeU8(w, dx);
1118 else if(dx<0 && dx>=-255) writeU8(w, -dx);
1119 else if(dx) writeS16(w, dx);
1123 for(s=0;s<g->num_points;s++) {
1124 ttfpoint_t*p = &g->points[s];
1125 int dy = p->y - lasty;
1126 if(dy>32767 || dy<-32768) {
1127 msg("<error> Coordinate overflow in glyph");
1130 if(dy>0 && dy<=255) writeU8(w, dy);
1131 else if(dy<0 && dy>=-255) writeU8(w, -dy);
1132 else if(dy) writeS16(w, dy);
1135 U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
1137 U32*locations = malloc(sizeof(U32)*(ttf->num_glyphs+1));
1139 for(t=0;t<ttf->num_glyphs;t++) {
1140 locations[t] = w->len;
1141 ttfglyph_t*g = &ttf->glyphs[t];
1143 int num_contours = 0;
1144 for(s=0;s<g->num_points;s++) {
1145 if(g->points[s].flags&GLYPH_CONTOUR_END)
1148 writeS16(w, num_contours?num_contours:1);
1149 writeS16(w, g->xmin);
1150 writeS16(w, g->ymin);
1151 writeS16(w, g->xmax);
1152 writeS16(w, g->ymax);
1155 /* some ttf parsers can't deal with zero contours, so in the case
1156 of an empty glyph, write a single point (0,0) */
1157 writeU16(w, 0); //endpoint of 1st contour
1158 writeU16(w, g->code_size);
1160 writeBlock(w, g->code, g->code_size);
1161 writeU8(w, 0x31); //flag (xy=(0,0),on curve)
1163 write_simple_glyph(w, g);
1166 locations[t] = w->len;
1169 void glyf_dump(ttf_t* ttf)
1171 if(!ttf->glyphs) return;
1173 for(t=0;t<ttf->num_glyphs;t++) {
1174 ttfglyph_t*g = &ttf->glyphs[t];
1175 printf("glyph %d)\n", t);
1176 printf(" advance=%d\n", g->advance);
1177 printf(" bearing=%d\n", g->bearing);
1178 printf(" bbox=(%d/%d/%d/%d)\n", g->xmin, g->ymin, g->xmax, g->ymax);
1179 printf(" points=(");
1181 for(s=0;s<g->num_points;s++) {
1183 printf("%d/%d/0x%02x", g->points[s].x, g->points[s].y, g->points[s].flags);
1187 hexdump(g->code, g->code_size, " ");
1190 void glyf_delete(ttf_t* ttf)
1195 for(t=0;t<ttf->num_glyphs;t++) {
1196 if(ttf->glyphs[t].code) {
1197 free(ttf->glyphs[t].code);
1198 ttf->glyphs[t].code = 0;
1200 if(ttf->glyphs[t].points) {
1201 free(ttf->glyphs[t].points);
1202 ttf->glyphs[t].points = 0;
1205 free(ttf->glyphs);ttf->glyphs=0;
1208 static void grow_unicode(ttf_t*ttf, int index)
1212 ttf->unicode = rfx_calloc(sizeof(ttf->unicode[0])*size);
1213 } else if(ttf->unicode_size<size) {
1214 ttf->unicode = rfx_realloc(ttf->unicode, sizeof(ttf->unicode[0])*size);
1215 memset(ttf->unicode+ttf->unicode_size, 0, sizeof(ttf->unicode[0])*(size - ttf->unicode_size));
1217 ttf->unicode_size = size;
1219 void cmap_parse(memreader_t*r, ttf_t*ttf)
1221 readU16(r); // version (0)
1222 int num_subtables = readU16(r);
1225 if(r->pos+num_subtables*8 > r->size) {
1226 msg("<warning> CMap overflow");
1227 num_subtables = (r->size-r->pos)/8;
1230 for(t=0;t<num_subtables;t++) {
1231 U16 platform = readU16(r);
1232 U16 encoding = readU16(r);
1233 U32 offset = readU32(r);
1234 if(offset>r->size) {
1235 msg("<warning> CMAP table %d %d is out of bounds (%d)", platform, encoding, offset);
1239 int is_unicode = platform==0 ||
1240 platform==3 && encoding == 1 ||
1241 platform==3 && encoding == 10;
1246 INIT_READ(t, r->mem, r->size, offset);
1247 U16 format = readU16(&t);
1248 int length = readU16(&t);
1249 U16 language = readU16(&t);
1252 msg("<warning> Language code %02x in unicode mapping", language);
1257 if(t.pos+length > t.size) {
1258 msg("<warning> overflow in format 0 cmap table");
1261 data = malloc(num*sizeof(unicode_t));
1263 grow_unicode(ttf, num);
1264 for(s=0;s<num;s++) {
1265 ttf->unicode[s] = readU8(&t);
1267 } else if(format == 4) {
1268 U16 segment_count = readU16(&t);
1269 if(segment_count&1) {
1270 msg("<error> Bad segmentx2 count %d", segment_count);
1274 readU16(&t); //searchrange
1275 readU16(&t); //entry selector
1276 readU16(&t); //range shift
1277 INIT_READ(r_end, t.mem, t.size, t.pos);
1278 INIT_READ(r_start, t.mem, t.size, t.pos+2+segment_count*2);
1279 INIT_READ(r_delta, t.mem, t.size, t.pos+2+segment_count*4);
1280 INIT_READ(r_range, t.mem, t.size, t.pos+2+segment_count*6);
1281 int glyphmap_start = t.pos+2+segment_count*8;
1282 int glyphmap_size = t.size - glyphmap_start;
1284 for(s=0;s<segment_count;s++) {
1285 U16 start = readU16(&r_start);
1286 U16 end = readU16(&r_end);
1287 U16 delta = readU16(&r_delta);
1288 U16 range = readU16(&r_range);
1289 if(start==0xffff && end==0xffff && delta==1) {
1290 /* this is a common (maybe even required) occurence in fonts
1291 which explicitly map "unicode undefined" (0xffff) to
1292 "glyph undefined" (0).
1293 We don't want to blow our unicode table up to 65536 just
1294 because of this, so ignore this entry.
1298 grow_unicode(ttf, end);
1301 for(u=start;u<=end;u++) {
1302 ttf->unicode[u] = (u + delta) & 0xffff;
1305 int pos = r_range.pos-2+range;
1306 if(warn && pos+end-start+1 > t.size) {
1307 msg("<warning> glyphmap index out of bounds (%d-%d/%d)", pos, pos+end-start, t.size);
1310 INIT_READ(g, t.mem, t.size, pos);
1311 for(u=start;u<=end;u++) {
1312 ttf->unicode[u] = readU16(&g);
1319 static int segment_size(unicode_t*unicode, int pos, int size)
1323 for(s=pos;s<size;s++) {
1327 /* a segment costs us 8 bytes, so for more than 4 consecutive
1328 zero entries (16 bit each) in the glyph index array,
1329 it pays off to start a new segment */
1333 s -= count; // go to the last filled in entry
1338 void cmap_write(ttf_t* ttf, ttf_table_t*w)
1340 writeU16(w, 0); //version
1341 writeU16(w, 2); //two tables
1343 writeU16(w, 0); //platform (unicode)
1344 writeU16(w, 3); //encoding (unicode 2.0)
1345 writeU32(w, 20); //offset
1347 writeU16(w, 3); //platform (windows)
1348 writeU16(w, 1); //encoding (unicode basic multilingual plane UCS-2)
1349 writeU32(w, 20); //offset
1351 writeU16(w, 4); // format=4
1352 int length_pos = w->len;
1353 writeU16(w, 0); // length: we don't know yet
1354 writeU16(w, 0); // language (n/a for unicode)
1355 int num_segments_pos = w->len;
1356 writeU16(w, 0); //number of segments: we don't know yet either
1357 writeU16(w, 0); //searchrange
1358 writeU16(w, 0); //entry selector
1359 writeU16(w, 0); //range shift
1363 while(pos < ttf->unicode_size) {
1364 if(!ttf->unicode[pos]) {
1368 int s = segment_size(ttf->unicode, pos, ttf->unicode_size);
1373 num_segments++; // account for 0xffff mapping
1375 int glyphmap_start = w->len+2+num_segments*8;
1378 int end_pos = w->len;
1379 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
1380 writeU16(w, 0); //reserved byte
1381 int start_pos = w->len;
1382 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //start array
1383 int delta_pos = w->len;
1384 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //delta array
1385 int range_pos = w->len;
1386 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //range array
1388 w->data[num_segments_pos]=(num_segments*2)>>8;
1389 w->data[num_segments_pos+1]=(num_segments*2);
1393 while(pos < ttf->unicode_size) {
1394 if(!ttf->unicode[pos]) {
1398 U16 end = segment_size(ttf->unicode, pos, ttf->unicode_size);
1399 w->data[end_pos++]=end>>8;
1400 w->data[end_pos++]=end;
1401 w->data[start_pos++]=pos>>8;
1402 w->data[start_pos++]=pos;
1404 U16 delta = ttf->unicode[pos]-pos;
1406 for(s=pos+1;s<=end;s++) {
1407 U16 delta2 = ttf->unicode[s]-s;
1418 range = w->len - range_pos;
1419 for(s=pos;s<=end;s++) {
1420 writeU16(w, ttf->unicode[s]);
1423 w->data[delta_pos++]=delta>>8;
1424 w->data[delta_pos++]=delta;
1425 w->data[range_pos++]=range>>8;
1426 w->data[range_pos++]=range;
1431 /* write out a mapping from 0xffff to 0- seems to be required
1432 by some libraries (e.g. fonttools) */
1433 w->data[end_pos++]=0xff;
1434 w->data[end_pos++]=0xff;
1435 w->data[start_pos++]=0xff;
1436 w->data[start_pos++]=0xff;
1437 w->data[delta_pos++]=0;
1438 w->data[delta_pos++]=1;
1439 w->data[range_pos++]=0;
1440 w->data[range_pos++]=0;
1442 w->data[length_pos]=(w->len-20)>>8;
1443 w->data[length_pos+1]=w->len-20;
1445 void cmap_delete(ttf_t*ttf)
1451 ttf->unicode_size=0;
1453 void name_parse(memreader_t*r, ttf_t*ttf)
1455 U16 format = readU16(r);
1456 U16 count = readU16(r);
1457 U16 offset = readU16(r);
1460 for(t=0;t<count;t++) {
1461 U16 platform = readU16(r);
1462 U16 encoding = readU16(r);
1463 U16 language = readU16(r);
1464 U16 name_id = readU16(r);
1465 U16 len = readU16(r);
1466 U16 offset_2 = readU16(r);
1470 ttf->name = strdup_n(&r->mem[offset+offset_2], len);
1474 void name_write(ttf_t*ttf, ttf_table_t*table)
1476 writeU16(table, 0); //format
1477 writeU16(table, 1); //count
1479 writeU16(table, offset); //offset
1481 writeU16(table, 1); //platform id
1482 writeU16(table, 0); //encoding id
1483 writeU16(table, 0); //language
1484 writeU16(table, 4); //4: full name
1485 int len = strlen(ttf->name);
1486 writeU16(table, len);
1487 writeU16(table, table->len+2 - offset);
1489 for(t=0;t<len;t++) {
1490 writeU8(table, ttf->name[t]);
1493 void name_delete(ttf_t*ttf)
1501 static table_post_t*post_new(ttf_t*ttf)
1503 table_post_t*post = rfx_calloc(sizeof(table_post_t));
1506 void post_parse(memreader_t*r, ttf_t*ttf)
1508 table_post_t*post = ttf->post = rfx_calloc(sizeof(table_post_t));
1509 U16 format = readU16(r);
1510 post->italic_angle = readU16(r);
1511 post->underline_position = readU16(r);
1512 post->underline_thickness = readU16(r);
1513 U16 is_monospaced = readU16(r);
1514 readU16(r); // min mem 42
1516 readU16(r); // min mem 1
1519 void post_write(ttf_t*ttf, ttf_table_t*table)
1521 table_post_t*post = ttf->post;
1522 writeU32(table, 0x00030000);
1523 writeU32(table, post->italic_angle);
1524 writeU16(table, post->underline_position);
1525 writeU16(table, post->underline_thickness);
1526 writeU32(table, 0); //is monospaced TODO
1527 writeU32(table, 0); //min mem 42
1529 writeU32(table, 0); //min mem 1
1532 void post_delete(ttf_t*ttf)
1540 static int ttf_parse_tables(ttf_t*ttf)
1544 table = ttf_find_table(ttf, TAG_HEAD);
1546 msg("<error> Font has no head table");
1549 INIT_READ(m, table->data, table->len, 0);
1550 int loc_index = head_parse(ttf, &m);
1551 ttf_table_delete(ttf, table);
1553 table = ttf_find_table(ttf, TAG_MAXP);
1555 msg("<error> Font has no maxp table");
1558 INIT_READ(m2, table->data, table->len, 0);
1559 ttf->maxp = maxp_parse(ttf, &m2);
1560 ttf_table_delete(ttf, table);
1562 if(!ttf->num_glyphs) {
1563 msg("<error> Invalid number of characters");
1566 ttf->glyphs = rfx_calloc(sizeof(ttfglyph_t)*ttf->num_glyphs);
1568 table = ttf_find_table(ttf, TAG_OS2);
1570 INIT_READ(m, table->data, table->len, 0);
1571 ttf->os2 = os2_parse(&m);
1572 ttf_table_delete(ttf, table);
1575 table = ttf_find_table(ttf, TAG_HHEA);
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_HMTX);
1583 INIT_READ(m, table->data, table->len, 0);
1584 mtx_parse(&m, ttf, num_advances);
1585 ttf_table_delete(ttf, table);
1588 table = ttf_find_table(ttf, TAG_VHEA);
1591 INIT_READ(m, table->data, table->len, 0);
1592 int num_advances = hea_parse(&m, ttf);
1593 ttf_table_delete(ttf, table);
1595 table = ttf_find_table(ttf, TAG_VMTX);
1597 INIT_READ(m, table->data, table->len, 0);
1598 mtx_parse(&m, ttf, num_advances);
1599 ttf_table_delete(ttf, table);
1602 msg("<error> Font contains neither HHEA nor VHEA");
1605 table = ttf_find_table(ttf, TAG_LOCA);
1607 INIT_READ(m, table->data, table->len, 0);
1608 U32*loca = loca_parse(&m, ttf, loc_index);
1609 ttf_table_delete(ttf, table);
1610 table = ttf_find_table(ttf, TAG_GLYF);
1612 INIT_READ(m, table->data, table->len, 0);
1613 glyf_parse(&m, ttf, loca);
1614 ttf_table_delete(ttf, table);
1619 table = ttf_find_table(ttf, TAG_CMAP);
1621 INIT_READ(m, table->data, table->len, 0);
1622 cmap_parse(&m, ttf);
1623 ttf_table_delete(ttf, table);
1626 table = ttf_find_table(ttf, TAG_NAME);
1628 INIT_READ(m, table->data, table->len, 0);
1629 name_parse(&m, ttf);
1630 ttf_table_delete(ttf, table);
1633 table = ttf_find_table(ttf, TAG_POST);
1635 INIT_READ(m, table->data, table->len, 0);
1636 post_parse(&m, ttf);
1637 ttf_table_delete(ttf, table);
1642 static void ttf_collapse_tables(ttf_t*ttf)
1646 table = ttf_addtable(ttf, TAG_MAXP);
1647 maxp_write(ttf, table);
1650 table = ttf_addtable(ttf, TAG_OS2);
1651 os2_write(ttf, table);
1654 if(!ttf->is_vertical) {
1655 table = ttf_addtable(ttf, TAG_HMTX);
1656 int num_advances = mtx_write(ttf, table);
1657 table = ttf_addtable(ttf, TAG_HHEA);
1658 hea_write(ttf, table, num_advances);
1660 table = ttf_addtable(ttf, TAG_VMTX);
1661 int num_advances = mtx_write(ttf, table);
1662 table = ttf_addtable(ttf, TAG_VHEA);
1663 hea_write(ttf, table, num_advances);
1667 if(ttf->num_glyphs) {
1668 table = ttf_addtable(ttf, TAG_CMAP);
1669 cmap_write(ttf, table);
1672 table = ttf_addtable(ttf, TAG_GLYF);
1673 U32*locations = glyf_write(ttf, table);
1676 table = ttf_addtable(ttf, TAG_LOCA);
1677 loca_size = loca_write(ttf, table, locations);
1682 table = ttf_addtable(ttf, TAG_NAME);
1683 name_write(ttf, table);
1687 table = ttf_addtable(ttf, TAG_POST);
1688 post_write(ttf, table);
1692 table = ttf_addtable(ttf, TAG_HEAD);
1693 head_write(ttf, table, loca_size);
1699 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1700 ttf->version = VERSION_1_0;
1703 ttf_t* ttf_load(void*data, int length)
1705 INIT_READ(r,data,length, 0);
1708 msg("<error> Truncated Truetype file (%d bytes)", length);
1712 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1713 ttf->version = readU32(&r);
1714 if(ttf->version == TTCFTAG) {
1715 /* a ttc collection is a number of truetype fonts
1716 packaged together */
1718 msg("<error> Truncated TTC file (%d bytes)", length);
1721 U32 ttcf_version = readU32(&r); // 0x00000100: v1.0, 0x00000200: v2.0, includes DSIG table
1722 U32 num_fonts = readU32(&r); // number of fonts
1723 U32 font1_position = readU32(&r);
1724 if(font1_position+12 > length) {\
1725 msg("<error> Truncated TTC file (%d bytes, first font at %d)", length, font1_position);
1728 r.pos = font1_position;
1729 ttf->version = readU32(&r);
1732 int num_tables = readU16(&r);
1734 readU16(&r); //search range
1735 readU16(&r); //entry selector
1736 readU16(&r); //range shift
1738 if(num_tables*16 > length) {
1739 msg("<error> Truncated TTC file (table entries: %d)", num_tables);
1740 if(ttf->version != OPENTYPE &&
1741 ttf->version != TRUETYPE_MACOS &&
1742 ttf->version != VERSION_1_0) {
1743 // bad table length, weird version. This is probably not a ttf file.
1748 U32*table_data = malloc(16*num_tables);
1750 for(t=0;t<num_tables*4;t++) {
1751 table_data[t] = readU32(&r);
1753 for(t=0;t<num_tables;t++) {
1754 U32 tag = table_data[t*4];
1755 U32 checksum = table_data[t*4+1];
1756 U32 pos = table_data[t*4+2];
1757 U32 len = table_data[t*4+3];
1759 if(pos+len > length) {
1760 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);
1762 U8*mem = malloc(len);
1764 readBlock(&r, mem, len);
1766 ttf_table_t*table = ttf_addtable(ttf, tag);
1768 table->len = table->memsize = len;
1770 U32 checksum2 = ttf_table_checksum(table);
1771 if(checksum2!=checksum) {
1772 msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x",
1773 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1774 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1775 len, checksum2, checksum);
1782 if(!ttf_parse_tables(ttf))
1787 void ttf_create_truetype_tables(ttf_t*ttf)
1790 ttf->head = head_new(ttf);
1792 ttf->maxp = maxp_new(ttf);
1794 ttf->hea = hea_new(ttf);
1796 ttf->os2 = os2_new(ttf);
1798 ttf->post = post_new(ttf);
1800 ttf_table_t* ttf_write(ttf_t*ttf)
1802 ttf_collapse_tables(ttf);
1804 ttf_table_t*file = ttf_table_new(0);
1805 writeU32(file, VERSION_1_0);
1807 /* write number of tables */
1809 ttf_table_t*t = ttf->tables;
1814 writeU16(file, num_tables);
1816 /* write search range */
1817 int tmp = num_tables;
1818 int search_range = 0;
1825 writeU16(file, search_range);
1827 /* write entry selector */
1828 int entry_selector = 0;
1833 writeU16(file, entry_selector);
1835 /* write range shift */
1836 int range_shift = num_tables*16 - search_range;
1837 writeU16(file, range_shift);
1839 /* write table dictionary */
1840 int table_dictionary_pos = file->len;
1841 int data_pos = file->len + num_tables*16;
1842 for(t=ttf->tables;t;t=t->next) {
1843 writeU32(file, t->id);
1844 writeU32(file, ttf_table_checksum(t));
1845 writeU32(file, data_pos);
1846 writeU32(file, t->len);
1848 data_pos += (-t->len)&3; //pad
1853 U8 zero[4]={0,0,0,0};
1854 for(t=ttf->tables;t;t=t->next) {
1855 if(t->id == TAG_HEAD)
1856 head_pos = file->len;
1857 writeBlock(file, t->data, t->len);
1858 writeBlock(file, zero, (-t->len)&3); //pad
1860 U32 checksum = 0xb1b0afba - ttf_table_checksum(file);
1861 U8*checksum2 = file->data + head_pos + 8;
1862 checksum2[0] = checksum>>24;
1863 checksum2[1] = checksum>>16;
1864 checksum2[2] = checksum>>8;
1865 checksum2[3] = checksum>>0;
1868 void ttf_save(ttf_t*ttf, const char*filename)
1870 ttf_table_t* t = ttf_write(ttf);
1871 FILE*fi = fopen(filename, "wb");
1876 fwrite(t->data, t->len, 1, fi);
1878 ttf_table_delete(0, t);
1880 void ttf_dump(ttf_t*ttf)
1882 msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
1883 ttf_table_t*table = ttf->tables;
1885 U32 tag = table->id;
1886 msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)",
1887 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1888 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
1889 table = table->next;
1891 //ttf_table_dump(ttf_find_table(ttf, TAG_MAXP));
1899 void ttf_destroy_tables(ttf_t*ttf)
1901 ttf_table_t*table = ttf->tables;
1903 ttf_table_t*next = table->next;
1910 void ttf_reduce(ttf_t*ttf)
1912 ttf_destroy_tables(ttf);
1914 void ttf_destroy(ttf_t*ttf)
1916 ttf_destroy_tables(ttf);
1928 int main(int argn, const char*argv[])
1930 setConsoleLogging(7);
1931 const char*filename = "comic.ttf";
1934 //msg("<notice> Loading %s", filename);
1935 memfile_t*m = memfile_open(filename);
1936 ttf_t*ttf = ttf_load(m->data, m->len);
1938 msg("<error> Couldn't load %s", filename);
1942 ttf->name = strdup("testfont");
1946 //printf("os2 version: %04x (%d), maxp size: %d\n",
1947 // ttf->os2->version, ttf->os2->size, ttf->maxp->size);
1948 ttf_save(ttf, "testfont.ttf");