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);
1224 if(r->pos+num_subtables*8 > r->size) {
1225 msg("<warning> CMap overflow");
1226 num_subtables = (r->size-r->pos)/8;
1229 for(t=0;t<num_subtables;t++) {
1230 U16 platform = readU16(r);
1231 U16 encoding = readU16(r);
1232 U32 offset = readU32(r);
1233 if(offset>r->size) {
1234 msg("<warning> CMAP table %d %d is out of bounds (%d)", platform, encoding, offset);
1238 int is_unicode = platform==0 ||
1239 platform==3 && encoding == 1 ||
1240 platform==3 && encoding == 10;
1245 INIT_READ(t, r->mem, r->size, offset);
1246 U16 format = readU16(&t);
1247 int length = readU16(&t);
1248 U16 language = readU16(&t);
1251 msg("<warning> Language code %02x in unicode mapping", language);
1256 if(t.pos+length > t.size) {
1257 msg("<warning> overflow in format 0 cmap table");
1260 data = malloc(num*sizeof(unicode_t));
1262 grow_unicode(ttf, num);
1263 for(s=0;s<num;s++) {
1264 ttf->unicode[s] = readU8(&t);
1266 } else if(format == 4) {
1267 U16 segment_count = readU16(&t);
1268 if(segment_count&1) {
1269 msg("<error> Bad segmentx2 count %d", segment_count);
1273 readU16(&t); //searchrange
1274 readU16(&t); //entry selector
1275 readU16(&t); //range shift
1276 INIT_READ(r_end, t.mem, t.size, t.pos);
1277 INIT_READ(r_start, t.mem, t.size, t.pos+2+segment_count*2);
1278 INIT_READ(r_delta, t.mem, t.size, t.pos+2+segment_count*4);
1279 INIT_READ(r_range, t.mem, t.size, t.pos+2+segment_count*6);
1280 int glyphmap_start = t.pos+2+segment_count*8;
1281 int glyphmap_size = t.size - glyphmap_start;
1283 for(s=0;s<segment_count;s++) {
1284 U16 start = readU16(&r_start);
1285 U16 end = readU16(&r_end);
1286 U16 delta = readU16(&r_delta);
1287 U16 range = readU16(&r_range);
1288 if(start==0xffff && end==0xffff && delta==1) {
1289 /* this is a common (maybe even required) occurence in fonts
1290 which explicitly map "unicode undefined" (0xffff) to
1291 "glyph undefined" (0).
1292 We don't want to blow our unicode table up to 65536 just
1293 because of this, so ignore this entry.
1297 grow_unicode(ttf, end);
1300 for(u=start;u<=end;u++) {
1301 ttf->unicode[u] = (u + delta) & 0xffff;
1304 int pos = r_range.pos-2+range;
1305 if(warn && pos+end-start+1 > t.size) {
1306 msg("<warning> glyphmap index out of bounds (%d-%d/%d)", pos, pos+end-start, t.size);
1309 INIT_READ(g, t.mem, t.size, pos);
1310 for(u=start;u<=end;u++) {
1311 ttf->unicode[u] = readU16(&g);
1318 static int segment_size(unicode_t*unicode, int pos, int size)
1322 for(s=pos;s<size;s++) {
1326 /* a segment costs us 8 bytes, so for more than 4 consecutive
1327 zero entries (16 bit each) in the glyph index array,
1328 it pays off to start a new segment */
1332 s -= count; // go to the last filled in entry
1337 void cmap_write(ttf_t* ttf, ttf_table_t*w)
1339 writeU16(w, 0); //version
1340 writeU16(w, 2); //two tables
1342 writeU16(w, 0); //platform (unicode)
1343 writeU16(w, 3); //encoding (unicode 2.0)
1344 writeU32(w, 20); //offset
1346 writeU16(w, 3); //platform (windows)
1347 writeU16(w, 1); //encoding (unicode basic multilingual plane UCS-2)
1348 writeU32(w, 20); //offset
1350 writeU16(w, 4); // format=4
1351 int length_pos = w->len;
1352 writeU16(w, 0); // length: we don't know yet
1353 writeU16(w, 0); // language (n/a for unicode)
1354 int num_segments_pos = w->len;
1355 writeU16(w, 0); //number of segments: we don't know yet either
1356 writeU16(w, 0); //searchrange
1357 writeU16(w, 0); //entry selector
1358 writeU16(w, 0); //range shift
1362 while(pos < ttf->unicode_size) {
1363 if(!ttf->unicode[pos]) {
1367 int s = segment_size(ttf->unicode, pos, ttf->unicode_size);
1372 num_segments++; // account for 0xffff mapping
1374 int glyphmap_start = w->len+2+num_segments*8;
1377 int end_pos = w->len;
1378 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
1379 writeU16(w, 0); //reserved byte
1380 int start_pos = w->len;
1381 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //start array
1382 int delta_pos = w->len;
1383 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //delta array
1384 int range_pos = w->len;
1385 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //range array
1387 w->data[num_segments_pos]=(num_segments*2)>>8;
1388 w->data[num_segments_pos+1]=(num_segments*2);
1392 while(pos < ttf->unicode_size) {
1393 if(!ttf->unicode[pos]) {
1397 U16 end = segment_size(ttf->unicode, pos, ttf->unicode_size);
1398 w->data[end_pos++]=end>>8;
1399 w->data[end_pos++]=end;
1400 w->data[start_pos++]=pos>>8;
1401 w->data[start_pos++]=pos;
1403 U16 delta = ttf->unicode[pos]-pos;
1405 for(s=pos+1;s<=end;s++) {
1406 U16 delta2 = ttf->unicode[s]-s;
1417 range = w->len - range_pos;
1418 for(s=pos;s<=end;s++) {
1419 writeU16(w, ttf->unicode[s]);
1422 w->data[delta_pos++]=delta>>8;
1423 w->data[delta_pos++]=delta;
1424 w->data[range_pos++]=range>>8;
1425 w->data[range_pos++]=range;
1430 /* write out a mapping from 0xffff to 0- seems to be required
1431 by some libraries (e.g. fonttools) */
1432 w->data[end_pos++]=0xff;
1433 w->data[end_pos++]=0xff;
1434 w->data[start_pos++]=0xff;
1435 w->data[start_pos++]=0xff;
1436 w->data[delta_pos++]=0;
1437 w->data[delta_pos++]=1;
1438 w->data[range_pos++]=0;
1439 w->data[range_pos++]=0;
1441 w->data[length_pos]=(w->len-20)>>8;
1442 w->data[length_pos+1]=w->len-20;
1444 void cmap_delete(ttf_t*ttf)
1450 ttf->unicode_size=0;
1452 void name_parse(memreader_t*r, ttf_t*ttf)
1454 U16 format = readU16(r);
1455 U16 count = readU16(r);
1456 U16 offset = readU16(r);
1459 for(t=0;t<count;t++) {
1460 U16 platform = readU16(r);
1461 U16 encoding = readU16(r);
1462 U16 language = readU16(r);
1463 U16 name_id = readU16(r);
1464 U16 len = readU16(r);
1465 U16 offset_2 = readU16(r);
1469 ttf->name = strdup_n(&r->mem[offset+offset_2], len);
1473 void name_write(ttf_t*ttf, ttf_table_t*table)
1475 writeU16(table, 0); //format
1476 writeU16(table, 1); //count
1478 writeU16(table, offset); //offset
1480 writeU16(table, 1); //platform id
1481 writeU16(table, 0); //encoding id
1482 writeU16(table, 0); //language
1483 writeU16(table, 4); //4: full name
1484 int len = strlen(ttf->name);
1485 writeU16(table, len);
1486 writeU16(table, table->len+2 - offset);
1488 for(t=0;t<len;t++) {
1489 writeU8(table, ttf->name[t]);
1492 void name_delete(ttf_t*ttf)
1500 static table_post_t*post_new(ttf_t*ttf)
1502 table_post_t*post = rfx_calloc(sizeof(table_post_t));
1505 void post_parse(memreader_t*r, ttf_t*ttf)
1507 table_post_t*post = ttf->post = rfx_calloc(sizeof(table_post_t));
1508 U16 format = readU16(r);
1509 post->italic_angle = readU16(r);
1510 post->underline_position = readU16(r);
1511 post->underline_thickness = readU16(r);
1512 U16 is_monospaced = readU16(r);
1513 readU16(r); // min mem 42
1515 readU16(r); // min mem 1
1518 void post_write(ttf_t*ttf, ttf_table_t*table)
1520 table_post_t*post = ttf->post;
1521 writeU32(table, 0x00030000);
1522 writeU32(table, post->italic_angle);
1523 writeU16(table, post->underline_position);
1524 writeU16(table, post->underline_thickness);
1525 writeU32(table, 0); //is monospaced TODO
1526 writeU32(table, 0); //min mem 42
1528 writeU32(table, 0); //min mem 1
1531 void post_delete(ttf_t*ttf)
1539 static int ttf_parse_tables(ttf_t*ttf)
1543 table = ttf_find_table(ttf, TAG_HEAD);
1545 msg("<error> Font has no head table");
1548 INIT_READ(m, table->data, table->len, 0);
1549 int loc_index = head_parse(ttf, &m);
1550 ttf_table_delete(ttf, table);
1552 table = ttf_find_table(ttf, TAG_MAXP);
1554 msg("<error> Font has no maxp table");
1557 INIT_READ(m2, table->data, table->len, 0);
1558 ttf->maxp = maxp_parse(ttf, &m2);
1559 ttf_table_delete(ttf, table);
1561 if(!ttf->num_glyphs) {
1562 msg("<error> Invalid number of characters");
1565 ttf->glyphs = rfx_calloc(sizeof(ttfglyph_t)*ttf->num_glyphs);
1567 table = ttf_find_table(ttf, TAG_OS2);
1569 INIT_READ(m, table->data, table->len, 0);
1570 ttf->os2 = os2_parse(&m);
1571 ttf_table_delete(ttf, table);
1574 table = ttf_find_table(ttf, TAG_HHEA);
1576 INIT_READ(m, table->data, table->len, 0);
1577 int num_advances = hea_parse(&m, ttf);
1578 ttf_table_delete(ttf, table);
1580 table = ttf_find_table(ttf, TAG_HMTX);
1582 INIT_READ(m, table->data, table->len, 0);
1583 mtx_parse(&m, ttf, num_advances);
1584 ttf_table_delete(ttf, table);
1587 table = ttf_find_table(ttf, TAG_VHEA);
1590 INIT_READ(m, table->data, table->len, 0);
1591 int num_advances = hea_parse(&m, ttf);
1592 ttf_table_delete(ttf, table);
1594 table = ttf_find_table(ttf, TAG_VMTX);
1596 INIT_READ(m, table->data, table->len, 0);
1597 mtx_parse(&m, ttf, num_advances);
1598 ttf_table_delete(ttf, table);
1601 msg("<error> Font contains neither HHEA nor VHEA");
1604 table = ttf_find_table(ttf, TAG_LOCA);
1606 INIT_READ(m, table->data, table->len, 0);
1607 U32*loca = loca_parse(&m, ttf, loc_index);
1608 ttf_table_delete(ttf, table);
1609 table = ttf_find_table(ttf, TAG_GLYF);
1611 INIT_READ(m, table->data, table->len, 0);
1612 glyf_parse(&m, ttf, loca);
1613 ttf_table_delete(ttf, table);
1618 table = ttf_find_table(ttf, TAG_CMAP);
1620 INIT_READ(m, table->data, table->len, 0);
1621 cmap_parse(&m, ttf);
1622 ttf_table_delete(ttf, table);
1625 table = ttf_find_table(ttf, TAG_NAME);
1627 INIT_READ(m, table->data, table->len, 0);
1628 name_parse(&m, ttf);
1629 ttf_table_delete(ttf, table);
1632 table = ttf_find_table(ttf, TAG_POST);
1634 INIT_READ(m, table->data, table->len, 0);
1635 post_parse(&m, ttf);
1636 ttf_table_delete(ttf, table);
1641 static void ttf_collapse_tables(ttf_t*ttf)
1645 table = ttf_addtable(ttf, TAG_MAXP);
1646 maxp_write(ttf, table);
1649 table = ttf_addtable(ttf, TAG_OS2);
1650 os2_write(ttf, table);
1653 if(!ttf->is_vertical) {
1654 table = ttf_addtable(ttf, TAG_HMTX);
1655 int num_advances = mtx_write(ttf, table);
1656 table = ttf_addtable(ttf, TAG_HHEA);
1657 hea_write(ttf, table, num_advances);
1659 table = ttf_addtable(ttf, TAG_VMTX);
1660 int num_advances = mtx_write(ttf, table);
1661 table = ttf_addtable(ttf, TAG_VHEA);
1662 hea_write(ttf, table, num_advances);
1666 if(ttf->num_glyphs) {
1667 table = ttf_addtable(ttf, TAG_CMAP);
1668 cmap_write(ttf, table);
1671 table = ttf_addtable(ttf, TAG_GLYF);
1672 U32*locations = glyf_write(ttf, table);
1675 table = ttf_addtable(ttf, TAG_LOCA);
1676 loca_size = loca_write(ttf, table, locations);
1681 table = ttf_addtable(ttf, TAG_NAME);
1682 name_write(ttf, table);
1686 table = ttf_addtable(ttf, TAG_POST);
1687 post_write(ttf, table);
1691 table = ttf_addtable(ttf, TAG_HEAD);
1692 head_write(ttf, table, loca_size);
1698 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1699 ttf->version = VERSION_1_0;
1702 ttf_t* ttf_load(void*data, int length)
1704 INIT_READ(r,data,length, 0);
1707 msg("<error> Truncated Truetype file (%d bytes)", length);
1711 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1712 ttf->version = readU32(&r);
1713 if(ttf->version == TTCFTAG) {
1714 /* a ttc collection is a number of truetype fonts
1715 packaged together */
1717 msg("<error> Truncated TTC file (%d bytes)", length);
1720 U32 ttcf_version = readU32(&r); // 0x00000100: v1.0, 0x00000200: v2.0, includes DSIG table
1721 U32 num_fonts = readU32(&r); // number of fonts
1722 U32 font1_position = readU32(&r);
1723 if(font1_position+12 > length) {\
1724 msg("<error> Truncated TTC file (%d bytes, first font at %d)", length, font1_position);
1727 r.pos = font1_position;
1728 ttf->version = readU32(&r);
1731 int num_tables = readU16(&r);
1733 readU16(&r); //search range
1734 readU16(&r); //entry selector
1735 readU16(&r); //range shift
1737 if(num_tables*16 > length) {
1738 msg("<error> Truncated TTC file (table entries: %d)", num_tables);
1739 if(ttf->version != OPENTYPE &&
1740 ttf->version != TRUETYPE_MACOS &&
1741 ttf->version != VERSION_1_0) {
1742 // bad table length, weird version. This is probably not a ttf file.
1747 U32*table_data = malloc(16*num_tables);
1749 for(t=0;t<num_tables*4;t++) {
1750 table_data[t] = readU32(&r);
1752 for(t=0;t<num_tables;t++) {
1753 U32 tag = table_data[t*4];
1754 U32 checksum = table_data[t*4+1];
1755 U32 pos = table_data[t*4+2];
1756 U32 len = table_data[t*4+3];
1758 if(pos+len > length) {
1759 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);
1761 U8*mem = malloc(len);
1763 readBlock(&r, mem, len);
1765 ttf_table_t*table = ttf_addtable(ttf, tag);
1767 table->len = table->memsize = len;
1769 U32 checksum2 = ttf_table_checksum(table);
1770 if(checksum2!=checksum) {
1771 msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x",
1772 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1773 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1774 len, checksum2, checksum);
1781 if(!ttf_parse_tables(ttf))
1786 void ttf_create_truetype_tables(ttf_t*ttf)
1789 ttf->head = head_new(ttf);
1791 ttf->maxp = maxp_new(ttf);
1793 ttf->hea = hea_new(ttf);
1795 ttf->os2 = os2_new(ttf);
1797 ttf->post = post_new(ttf);
1799 ttf_table_t* ttf_write(ttf_t*ttf)
1801 ttf_collapse_tables(ttf);
1803 ttf_table_t*file = ttf_table_new(0);
1804 writeU32(file, VERSION_1_0);
1806 /* write number of tables */
1808 ttf_table_t*t = ttf->tables;
1813 writeU16(file, num_tables);
1815 /* write search range */
1816 int tmp = num_tables;
1817 int search_range = 0;
1824 writeU16(file, search_range);
1826 /* write entry selector */
1827 int entry_selector = 0;
1832 writeU16(file, entry_selector);
1834 /* write range shift */
1835 int range_shift = num_tables*16 - search_range;
1836 writeU16(file, range_shift);
1838 /* write table dictionary */
1839 int table_dictionary_pos = file->len;
1840 int data_pos = file->len + num_tables*16;
1841 for(t=ttf->tables;t;t=t->next) {
1842 writeU32(file, t->id);
1843 writeU32(file, ttf_table_checksum(t));
1844 writeU32(file, data_pos);
1845 writeU32(file, t->len);
1847 data_pos += (-t->len)&3; //pad
1852 U8 zero[4]={0,0,0,0};
1853 for(t=ttf->tables;t;t=t->next) {
1854 if(t->id == TAG_HEAD)
1855 head_pos = file->len;
1856 writeBlock(file, t->data, t->len);
1857 writeBlock(file, zero, (-t->len)&3); //pad
1859 U32 checksum = 0xb1b0afba - ttf_table_checksum(file);
1860 U8*checksum2 = file->data + head_pos + 8;
1861 checksum2[0] = checksum>>24;
1862 checksum2[1] = checksum>>16;
1863 checksum2[2] = checksum>>8;
1864 checksum2[3] = checksum>>0;
1867 void ttf_save(ttf_t*ttf, const char*filename)
1869 ttf_table_t* t = ttf_write(ttf);
1870 FILE*fi = fopen(filename, "wb");
1875 fwrite(t->data, t->len, 1, fi);
1877 ttf_table_delete(0, t);
1879 void ttf_dump(ttf_t*ttf)
1881 msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
1882 ttf_table_t*table = ttf->tables;
1884 U32 tag = table->id;
1885 msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)",
1886 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1887 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
1888 table = table->next;
1890 //ttf_table_dump(ttf_find_table(ttf, TAG_MAXP));
1898 void ttf_destroy_tables(ttf_t*ttf)
1900 ttf_table_t*table = ttf->tables;
1902 ttf_table_t*next = table->next;
1909 void ttf_reduce(ttf_t*ttf)
1911 ttf_destroy_tables(ttf);
1913 void ttf_destroy(ttf_t*ttf)
1915 ttf_destroy_tables(ttf);
1927 int main(int argn, const char*argv[])
1929 setConsoleLogging(7);
1930 const char*filename = "comic.ttf";
1933 //msg("<notice> Loading %s", filename);
1934 memfile_t*m = memfile_open(filename);
1935 ttf_t*ttf = ttf_load(m->data, m->len);
1937 msg("<error> Couldn't load %s", filename);
1941 ttf->name = strdup("testfont");
1945 //printf("os2 version: %04x (%d), maxp size: %d\n",
1946 // ttf->os2->version, ttf->os2->size, ttf->maxp->size);
1947 ttf_save(ttf, "testfont.ttf");