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 void writeU8(ttf_table_t*w, unsigned char b)
131 if(w->memsize<w->len+1)
133 w->data[w->len++] = b;
135 static 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 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 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_os2_t*os2_parse(memreader_t*r)
263 table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
264 U16 version = readU16(r);
265 if(version!=0 && version!=1 && version!=2)
266 msg("<warning> Unknown OS2 version: %04x", version);
267 os2->xAvgCharWidth = readS16(r);
268 os2->usWeightClass = readU16(r);
269 os2->usWidthClass = readU16(r);
270 os2->fsType = readU16(r);
271 os2->ySubscriptXSize = readU16(r);
272 os2->ySubscriptYSize = readU16(r);
273 os2->ySubscriptXOffset = readU16(r);
274 os2->ySubscriptYOffset = readU16(r);
275 os2->ySuperscriptXSize = readU16(r);
276 os2->ySuperscriptYSize = readU16(r);
277 os2->ySuperscriptXOffset = readU16(r);
278 os2->ySuperscriptYOffset = readU16(r);
279 os2->yStrikeoutSize = readU16(r);
280 os2->yStrikeoutPosition = readU16(r);
281 os2->sFamilyClass = readU16(r);
282 os2->panose_FamilyType = readU8(r);
283 os2->panose_SerifStyle = readU8(r);
284 os2->panose_Weight = readU8(r);
285 os2->panose_Proportion = readU8(r);
286 os2->panose_Contrast = readU8(r);
287 os2->panose_StrokeVariation = readU8(r);
288 os2->panose_ArmStyle = readU8(r);
289 os2->panose_Letterform = readU8(r);
290 os2->panose_Midline = readU8(r);
291 os2->panose_XHeight = readU8(r);
292 os2->ulCharRange[0] = readU32(r);
293 os2->ulCharRange[1] = readU32(r);
294 os2->ulCharRange[2] = readU32(r);
295 os2->ulCharRange[3] = readU32(r);
296 os2->achVendID[0] = readU8(r);
297 os2->achVendID[1] = readU8(r);
298 os2->achVendID[2] = readU8(r);
299 os2->achVendID[3] = readU8(r);
300 os2->fsSelection = readU16(r);
301 os2->fsFirstCharIndex = readU16(r);
302 os2->fsLastCharIndex = readU16(r);
303 os2->sTypoAscender = readS16(r);
304 os2->sTypoDescender = readS16(r);
305 os2->sTypoLineGap = readS16(r);
306 os2->usWinAscent = readU16(r);
307 os2->usWinDescent = readU16(r);
308 if(version<1) return os2;
309 os2->ulCodePageRange1 = readU32(r);
310 os2->ulCodePageRange2 = readU32(r);
311 if(version<2) return os2;
312 os2->sxHeight = readS16(r);
313 os2->sCapHeight = readS16(r);
314 os2->usDefaultChar = readU16(r);
315 os2->usBreakChar = readU16(r);
316 os2->usMaxContext = readU16(r);
320 static os2_write(ttf_t*ttf, ttf_table_t*w)
322 table_os2_t*os2 = ttf->os2;
324 if(os2->sxHeight|os2->sCapHeight|os2->usDefaultChar|os2->usBreakChar|os2->usMaxContext) {
327 writeU16(w, version);
328 writeS16(w, os2->xAvgCharWidth);
329 writeU16(w, os2->usWeightClass);
330 writeU16(w, os2->usWidthClass);
331 writeU16(w, os2->fsType);
332 writeU16(w, os2->ySubscriptXSize);
333 writeU16(w, os2->ySubscriptYSize);
334 writeU16(w, os2->ySubscriptXOffset);
335 writeU16(w, os2->ySubscriptYOffset);
336 writeU16(w, os2->ySuperscriptXSize);
337 writeU16(w, os2->ySuperscriptYSize);
338 writeU16(w, os2->ySuperscriptXOffset);
339 writeU16(w, os2->ySuperscriptYOffset);
340 writeU16(w, os2->yStrikeoutSize);
341 writeU16(w, os2->yStrikeoutPosition);
342 writeU16(w, os2->sFamilyClass);
343 writeU8(w, os2->panose_FamilyType);
344 writeU8(w, os2->panose_SerifStyle);
345 writeU8(w, os2->panose_Weight);
346 writeU8(w, os2->panose_Proportion);
347 writeU8(w, os2->panose_Contrast);
348 writeU8(w, os2->panose_StrokeVariation);
349 writeU8(w, os2->panose_ArmStyle);
350 writeU8(w, os2->panose_Letterform);
351 writeU8(w, os2->panose_Midline);
352 writeU8(w, os2->panose_XHeight);
353 writeU32(w, os2->ulCharRange[0]);
354 writeU32(w, os2->ulCharRange[1]);
355 writeU32(w, os2->ulCharRange[2]);
356 writeU32(w, os2->ulCharRange[3]);
357 writeU8(w, os2->achVendID[0]);
358 writeU8(w, os2->achVendID[1]);
359 writeU8(w, os2->achVendID[2]);
360 writeU8(w, os2->achVendID[3]);
361 writeU16(w, os2->fsSelection);
362 writeU16(w, os2->fsFirstCharIndex);
363 writeU16(w, os2->fsLastCharIndex);
364 writeS16(w, os2->sTypoAscender);
365 writeS16(w, os2->sTypoDescender);
366 writeS16(w, os2->sTypoLineGap);
367 writeU16(w, os2->usWinAscent);
368 writeU16(w, os2->usWinDescent);
369 if(version<1) return;
370 writeU32(w, os2->ulCodePageRange1);
371 writeU32(w, os2->ulCodePageRange2);
372 if(version<2) return;
373 writeS16(w, os2->sxHeight);
374 writeS16(w, os2->sCapHeight);
375 writeU16(w, os2->usDefaultChar);
376 writeU16(w, os2->usBreakChar);
377 writeU16(w, os2->usMaxContext);
379 static void os2_delete(ttf_t*ttf)
386 static os2_dump(ttf_t*ttf)
388 table_os2_t*os2 = ttf->os2;
390 printf("os2->xAvgCharWidth: %d\n", os2->xAvgCharWidth);
391 printf("os2->usWeightClass: %d\n", os2->usWeightClass);
392 printf("os2->usWidthClass: %d\n", os2->usWidthClass);
393 printf("os2->fsType: %d\n", os2->fsType);
394 printf("os2->ySubscriptXSize: %d\n", os2->ySubscriptXSize);
395 printf("os2->ySubscriptYSize: %d\n", os2->ySubscriptYSize);
396 printf("os2->ySubscriptXOffset: %d\n", os2->ySubscriptXOffset);
397 printf("os2->ySubscriptYOffset: %d\n", os2->ySubscriptYOffset);
398 printf("os2->ySuperscriptXSize: %d\n", os2->ySuperscriptXSize);
399 printf("os2->ySuperscriptYSize: %d\n", os2->ySuperscriptYSize);
400 printf("os2->ySuperscriptXOffset: %d\n", os2->ySuperscriptXOffset);
401 printf("os2->ySuperscriptYOffset: %d\n", os2->ySuperscriptYOffset);
402 printf("os2->yStrikeoutSize: %d\n", os2->yStrikeoutSize);
403 printf("os2->yStrikeoutPosition: %d\n", os2->yStrikeoutPosition);
404 printf("os2->sFamilyClass: %d\n", os2->sFamilyClass);
405 printf("os2->panose_FamilyType: %d\n", os2->panose_FamilyType);
406 printf("os2->panose_SerifStyle: %d\n", os2->panose_SerifStyle);
407 printf("os2->panose_Weight: %d\n", os2->panose_Weight);
408 printf("os2->panose_Proportion: %d\n", os2->panose_Proportion);
409 printf("os2->panose_Contrast: %d\n", os2->panose_Contrast);
410 printf("os2->panose_StrokeVariation: %d\n", os2->panose_StrokeVariation);
411 printf("os2->panose_ArmStyle: %d\n", os2->panose_ArmStyle);
412 printf("os2->panose_Letterform: %d\n", os2->panose_Letterform);
413 printf("os2->panose_Midline: %d\n", os2->panose_Midline);
414 printf("os2->panose_XHeight: %d\n", os2->panose_XHeight);
415 printf("os2->ulCharRange[0]: %d\n", os2->ulCharRange[0]);
416 printf("os2->ulCharRange[1]: %d\n", os2->ulCharRange[1]);
417 printf("os2->ulCharRange[2]: %d\n", os2->ulCharRange[2]);
418 printf("os2->ulCharRange[3]: %d\n", os2->ulCharRange[3]);
419 printf("os2->achVendID[0]: %d\n", os2->achVendID[0]);
420 printf("os2->achVendID[1]: %d\n", os2->achVendID[1]);
421 printf("os2->achVendID[2]: %d\n", os2->achVendID[2]);
422 printf("os2->achVendID[3]: %d\n", os2->achVendID[3]);
423 printf("os2->fsSelection: %d\n", os2->fsSelection);
424 printf("os2->fsFirstCharIndex: %d\n", os2->fsFirstCharIndex);
425 printf("os2->fsLastCharIndex: %d\n", os2->fsLastCharIndex);
426 printf("os2->sTypoAscender: %d\n", os2->sTypoAscender);
427 printf("os2->sTypoDescender: %d\n", os2->sTypoDescender);
428 printf("os2->sTypoLineGap: %d\n", os2->sTypoLineGap);
429 printf("os2->usWinAscent: %d\n", os2->usWinAscent);
430 printf("os2->usWinDescent: %d\n", os2->usWinDescent);
431 printf("os2->ulCodePageRange1: %d\n", os2->ulCodePageRange1);
432 printf("os2->ulCodePageRange2: %d\n", os2->ulCodePageRange2);
433 printf("os2->sxHeight: %d\n", os2->sxHeight);
434 printf("os2->sCapHeight: %d\n", os2->sCapHeight);
435 printf("os2->usDefaultChar: %d\n", os2->usDefaultChar);
436 printf("os2->usBreakChar: %d\n", os2->usBreakChar);
437 printf("os2->usMaxContext: %d\n", os2->usMaxContext);
440 static int head_parse(ttf_t*ttf, memreader_t*r)
442 ttf->head = rfx_calloc(sizeof(table_head_t));
443 U32 version = readU32(r);
444 if(version!=VERSION_1_0)
445 msg("<warning> Font HEAD has unknown version %08x", version);
446 U32 revision = readU32(r);
447 if(revision!=VERSION_1_0)
448 msg("<warning> Font HEAD has unknown revision %08x", revision);
449 U32 checksum2 = readU32(r);
450 U32 magic = readU32(r);
451 if(magic!=0x5f0f3cf5)
452 msg("<warning> Font HEAD has unknown magic number %08x", magic);
453 ttf->head->flags = readU16(r);
454 ttf->head->units_per_em = readU16(r);
455 readU32(r);readU32(r); //created
456 readU32(r);readU32(r); //modified
457 ttf->head->xmin = readU16(r);
458 ttf->head->ymin = readU16(r);
459 ttf->head->xmax = readU16(r);
460 ttf->head->ymax = readU16(r);
461 ttf->head->macStyle = readU16(r);
462 ttf->head->lowest_readable_size = readU16(r); //in pixels
463 ttf->head->dir_hint = readS16(r);
464 int loc_index = readS16(r); //used in 'loca' table
466 msg("<warning> loca index format %d unknown", loc_index);
467 U16 glyph_data_format = readS16(r);
468 if(glyph_data_format!=0)
469 msg("<warning> Font glyph data format unknown: %04x", glyph_data_format);
473 static void head_write(ttf_t*ttf, ttf_table_t*w, int loca_size)
475 writeU32(w, 0x10000);
476 writeU32(w, 0x10000);
477 writeU32(w, 0); //checksum
478 writeU32(w, 0x5f0f3cf5); //magic
479 writeU16(w, ttf->head->flags);
480 writeU16(w, ttf->head->units_per_em);
481 writeU32(w, 0);writeU32(w, 0); //created
482 writeU32(w, 0);writeU32(w, 0); //modified
483 writeU16(w, ttf->head->xmin);
484 writeU16(w, ttf->head->ymin);
485 writeU16(w, ttf->head->xmax);
486 writeU16(w, ttf->head->ymax);
487 writeU16(w, ttf->head->macStyle);
488 writeU16(w, ttf->head->lowest_readable_size);
489 writeS16(w, ttf->head->dir_hint);
490 writeS16(w, loca_size); //loca index size (32 bit)
491 writeS16(w, 0); //glyph data format
493 static void head_dump(ttf_t*ttf)
495 printf("head->flags: %d\n", ttf->head->flags);
496 printf("head->units_per_em: %d\n", ttf->head->units_per_em);
497 printf("head->xmin: %d\n", ttf->head->xmin);
498 printf("head->ymin: %d\n", ttf->head->ymin);
499 printf("head->xmax: %d\n", ttf->head->xmax);
500 printf("head->ymax: %d\n", ttf->head->ymax);
501 printf("head->macStyle: %d\n", ttf->head->macStyle);
502 printf("head->lowest_readable_size: %d\n", ttf->head->lowest_readable_size);
503 printf("head->dir_hint: %d\n", ttf->head->dir_hint);
505 static void head_delete(ttf_t*ttf)
513 static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r)
515 U32 version = readU32(r);
516 ttf->num_glyphs = readU16(r);
517 /* according to freetype, older fonts (version<0x10000)
518 apparently only contain the number of glyphs. this is
519 rather rare, though. */
520 if(version<0x10000) return 0;
522 table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t));
523 maxp->maxPoints = readU16(r);
524 maxp->maxContours = readU16(r);
525 maxp->maxComponentPoints = readU16(r);
526 maxp->maxComponentContours = readU16(r);
527 maxp->maxZones = readU16(r);
528 maxp->maxTwilightPoints = readU16(r);
529 maxp->maxStorage = readU16(r);
530 maxp->maxFunctionDefs = readU16(r);
531 maxp->maxInstructionDefs = readU16(r);
532 maxp->maxStackElements = readU16(r);
533 maxp->maxSizeOfInstructions = readU16(r);
534 maxp->maxComponentElements = readU16(r);
535 maxp->maxComponentDepth = readU16(r);
539 static void maxp_write(ttf_t*ttf, ttf_table_t*w)
541 table_maxp_t*maxp = ttf->maxp;
542 writeU32(w, 0x10000); //version
543 writeU16(w, ttf->num_glyphs);
544 writeU16(w, maxp->maxPoints);
545 writeU16(w, maxp->maxContours);
546 writeU16(w, maxp->maxComponentPoints);
547 writeU16(w, maxp->maxComponentContours);
548 writeU16(w, maxp->maxZones);
549 writeU16(w, maxp->maxTwilightPoints);
550 writeU16(w, maxp->maxStorage);
551 writeU16(w, maxp->maxFunctionDefs);
552 writeU16(w, maxp->maxInstructionDefs);
553 writeU16(w, maxp->maxStackElements);
554 writeU16(w, maxp->maxSizeOfInstructions);
555 writeU16(w, maxp->maxComponentElements);
556 writeU16(w, maxp->maxComponentDepth);
559 static void maxp_dump(ttf_t*ttf)
561 table_maxp_t*maxp = ttf->maxp;
563 printf("maxp->maxPoints: %d\n", maxp->maxPoints);
564 printf("maxp->maxContours: %d\n", maxp->maxContours);
565 printf("maxp->maxComponentPoints: %d\n", maxp->maxComponentPoints);
566 printf("maxp->maxComponentContours: %d\n", maxp->maxComponentContours);
567 printf("maxp->maxZones: %d\n", maxp->maxZones);
568 printf("maxp->maxTwilightPoints: %d\n", maxp->maxTwilightPoints);
569 printf("maxp->maxStorage: %d\n", maxp->maxStorage);
570 printf("maxp->maxFunctionDefs: %d\n", maxp->maxFunctionDefs);
571 printf("maxp->maxInstructionDefs: %d\n", maxp->maxInstructionDefs);
572 printf("maxp->maxStackElements: %d\n", maxp->maxStackElements);
573 printf("maxp->maxSizeOfInstructions: %d\n", maxp->maxSizeOfInstructions);
574 printf("maxp->maxComponentElements: %d\n", maxp->maxComponentElements);
575 printf("maxp->maxComponentDepth: %d\n", maxp->maxComponentDepth);
578 static void maxp_delete(ttf_t*ttf)
586 static int hea_parse(memreader_t*r, ttf_t*ttf)
588 table_hea_t*hea = ttf->hea = rfx_calloc(sizeof(table_hea_t));
589 U32 version = readU32(r);
590 hea->ascent = readS16(r);
591 hea->descent = readS16(r);
592 hea->lineGap = readS16(r);
593 hea->advanceWidthMax = readU16(r);
594 hea->minLeftSideBearing = readS16(r);
595 hea->minRightSideBearing = readS16(r);
596 hea->xMaxExtent = readS16(r);
597 hea->caretSlopeRise = readS16(r);
598 hea->caretSlopeRun = readS16(r);
599 hea->caretOffset = readS16(r);
600 readS16(r); //reserved[0]
601 readS16(r); //reserved[1]
602 readS16(r); //reserved[2]
603 readS16(r); //reserved[3]
604 S16 metricDataFormat = readS16(r); //should be 0
605 if(metricDataFormat!=0) {
606 msg("<warning> Unknown metric format %d", metricDataFormat);
608 int num_advances = readU16(r);
609 if(num_advances > ttf->num_glyphs) {
610 msg("<warning> bad number of horizontal metrics: %d", num_advances);
611 num_advances = ttf->num_glyphs;
616 static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances)
618 table_hea_t*hea = ttf->hea;
619 writeU32(w, 0x00010000);
620 writeS16(w, hea->ascent);
621 writeS16(w, hea->descent);
622 writeS16(w, hea->lineGap);
623 writeU16(w, hea->advanceWidthMax);
624 writeS16(w, hea->minLeftSideBearing);
625 writeS16(w, hea->minRightSideBearing);
626 writeS16(w, hea->xMaxExtent);
627 writeS16(w, hea->caretSlopeRise);
628 writeS16(w, hea->caretSlopeRun);
629 writeS16(w, hea->caretOffset);
630 writeS16(w, 0); //reserved
631 writeS16(w, 0); //reserved
632 writeS16(w, 0); //reserved
633 writeS16(w, 0); //reserved
634 writeS16(w, 0); //metricDataFormat
635 writeU16(w, num_advances);
638 static void hea_dump(ttf_t*ttf)
640 table_hea_t*hea = ttf->hea;
641 const char*dir = ttf->is_vertical?"v":"h";
642 printf("%shea->ascent: %d\n", dir, hea->ascent);
643 printf("%shea->descent: %d\n", dir, hea->descent);
644 printf("%shea->lineGap: %d\n", dir, hea->lineGap);
645 printf("%shea->advanceWidthMax: %d\n", dir, hea->advanceWidthMax);
646 printf("%shea->minLeftSideBearing: %d\n", dir, hea->minLeftSideBearing);
647 printf("%shea->minRightSideBearing: %d\n", dir, hea->minRightSideBearing);
648 printf("%shea->xMaxExtent: %d\n", dir, hea->xMaxExtent);
649 printf("%shea->caretSlopeRise: %d\n", dir, hea->caretSlopeRise);
650 printf("%shea->caretSlopeRun: %d\n", dir, hea->caretSlopeRun);
651 printf("%shea->caretOffset: %d\n", dir, hea->caretOffset);
653 static void hea_delete(ttf_t*ttf)
661 static void hmtx_parse(memreader_t*r, ttf_t*ttf, int num_advances)
665 if(num_advances > r->size/4)
666 num_advances = r->size/4;
667 for(t=0;t<num_advances;t++) {
668 old_advance = ttf->glyphs[t].advance = readU16(r);
669 ttf->glyphs[t].bearing = readS16(r);
671 int rest = (r->size - num_advances*4)/2;
672 if(ttf->num_glyphs < num_advances+rest) {
673 rest = ttf->num_glyphs-num_advances;
675 for(t=0;t<rest;t++) {
676 ttf->glyphs[t].advance = old_advance;
677 ttf->glyphs[t].bearing = readS16(r);
680 static int mtx_write(ttf_t*ttf, ttf_table_t*w)
682 int num_advances = ttf->num_glyphs;
683 if(ttf->num_glyphs>=2) {
685 for(t=ttf->num_glyphs-1;t>0;t--) {
686 if(ttf->glyphs[t-1].advance !=
687 ttf->glyphs[t].advance) break;
689 /* we need to store all individual advances as well
690 as one entry for the constant */
695 for(t=0;t<num_advances;t++) {
696 writeU16(w, ttf->glyphs[t].advance);
697 writeU16(w, ttf->glyphs[t].bearing);
699 for(;t<ttf->num_glyphs;t++) {
700 writeU16(w, ttf->glyphs[t].bearing);
704 static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size)
707 int num = ttf->num_glyphs+1;
708 U32*locations = rfx_calloc(num*sizeof(U32));
710 if(num*4 > r->size) {
711 msg("<warning> Short 'loca' table (32 bit)");
714 if(num*4 < r->size) {
715 msg("<warning> Extraneous data (%d bytes) in 'loca' table (32 bit)", r->size-num*4);
718 locations[t] = readU32(r);
721 if(num*2 > r->size) {
722 msg("<warning> Short 'loca' table (16 bit)");
725 if(num*2 < r->size) {
726 msg("<warning> Extraneous data (%d bytes) in 'loca' table (16 bit)", r->size-num*2);
729 locations[t] = readU16(r)*2;
734 static int loca_write(ttf_t*ttf, ttf_table_t*w, U32*locations)
738 for(t=0;t<=ttf->num_glyphs;t++) {
739 if(locations[t]>=0x20000 || (locations[t]&1)) {
746 for(t=0;t<=ttf->num_glyphs;t++) {
747 writeU32(w, locations[t]);
751 for(t=0;t<=ttf->num_glyphs;t++) {
752 writeU16(w, locations[t]/2);
757 static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int glyphnr)
759 ttfglyph_t*glyph = &ttf->glyphs[glyphnr];
763 endpoints = malloc(sizeof(U16)*num_contours);
766 for(s=0;s<num_contours;s++) {
767 int pos = endpoints[s] = readU16(r);
769 msg("<warning> Unsorted endpoints array (len:%d) last=%d now=%d", s, pos, lastpos);
774 U16 code_len = readU16(r);
776 glyph->code = malloc(sizeof(U16)*code_len);
777 readBlock(r, glyph->code, code_len);
778 glyph->code_size = code_len;
784 /*msg("<notice> TTF Glyph %d) code_size=%d num_contours=%d glyph->num_points=%d %d/%d/%d/%d",
785 glyphnr, code_len, num_contours, glyph->num_points,
786 xmin, ymin, xmax, ymax);*/
787 INIT_READ(fx, r->mem, r->size, r->pos);
788 INIT_READ(fy, r->mem, r->size, r->pos);
790 glyph->num_points = endpoints[num_contours-1] + 1;
791 glyph->points = rfx_calloc(sizeof(ttfpoint_t)*glyph->num_points);
793 /* parse flag array (1st pass- to determine start of coordinates) */
795 while(num<glyph->num_points) {
798 msg("<error> Bad flags in glyph outline: %02x (at pos %d)", flag, num);
801 glyph->num_points = 0;
807 if(count+num>glyph->num_points) {
808 msg("<warning> Bad count (%d) in glyph (%d) (at pos %d)", count, glyphnr, num);
809 count = glyph->num_points-num;
814 /* parse flag array (2nd pass) and x coordinates */
819 int bytepos = r->pos;
820 while(num<glyph->num_points) {
821 U8 flag = readU8(&fx);
822 int count = flag&8?readU8(&fx)+1:1;
823 count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
826 if(contour_pos<num_contours && num==endpoints[contour_pos]) {
831 if((flag&0x12) == 0x12) x += readU8(r);
832 else if((flag&0x12) == 0x02) x -= readU8(r);
833 else if((flag&0x12) == 0x00) x += readS16(r);
835 glyph->points[num].x = x;
836 U8 f = flag&GLYPH_ON_CURVE;
837 if(is_start) f|=GLYPH_CONTOUR_START;
838 if(is_end) f|=GLYPH_CONTOUR_END;
839 glyph->points[num].flags = f;
845 /* parse flag array (3rd pass) and y coordinates */
848 while(num<glyph->num_points) {
849 U8 flag = readU8(&fy);
850 int count = flag&8?readU8(&fy)+1:1;
851 count=count>glyph->num_points-num?glyph->num_points-num:(count?count:1);
853 if((flag&0x24) == 0x24) y += readU8(r);
854 else if((flag&0x24) == 0x04) y -= readU8(r);
855 else if((flag&0x24) == 0x00) y += readS16(r);
856 glyph->points[num].y = y;
863 static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca)
866 char warn_about_compound_glyphs=1;
867 for(t=0;t<ttf->num_glyphs;t++) {
868 INIT_READ(r, rr->mem, rr->size, loca[t]);
869 if(r.pos+10>r.size) {
870 msg("<warning> Unexpected end of glyph array (or bad loca entry %d/%d)", loca[t], r.size);
873 S16 num_contours = readS16(&r);
874 ttf->glyphs[t].xmin = readS16(&r);
875 ttf->glyphs[t].ymin = readS16(&r);
876 ttf->glyphs[t].xmax = readS16(&r);
877 ttf->glyphs[t].ymax = readS16(&r);
880 if(warn_about_compound_glyphs)
881 msg("<error> Compound glyphs not supported yet");
882 warn_about_compound_glyphs=0;
884 if(!parse_simple_glyph(ttf, &r, num_contours, t))
891 void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g)
893 /* endpoints array */
895 for(s=0;s<g->num_points;s++) {
896 if(g->points[s].flags&GLYPH_CONTOUR_END)
901 writeU16(w, g->code_size);
903 writeBlock(w, g->code, g->code_size);
910 for(s=0;s<g->num_points;s++) {
911 ttfpoint_t*p = &g->points[s];
912 int dx = p->x - lastx;
913 int dy = p->y - lasty;
914 U8 flags = p->flags&GLYPH_ON_CURVE;
917 } else if(dx<0 && dx>=-255) {
919 } else if(dx>0 && dx<=255) {
924 } else if(dy<0 && dy>=-255) {
926 } else if(dy>0 && dy<=255) {
929 if(flags == lastflag && flagcount<255) {
934 writeU8(w, lastflag|8);
935 writeU8(w, flagcount);
937 writeU8(w, lastflag);
948 writeU8(w, lastflag|8);
949 writeU8(w, flagcount);
951 writeU8(w, lastflag);
956 int bytepos = w->len;
957 for(s=0;s<g->num_points;s++) {
958 ttfpoint_t*p = &g->points[s];
959 int dx = p->x - lastx;
960 if(dx>32767 || dx<-32768) {
961 msg("<error> Coordinate overflow in glyph");
964 if(dx>0 && dx<=255) writeU8(w, dx);
965 else if(dx<0 && dx>=-255) writeU8(w, -dx);
966 else if(dx) writeS16(w, dx);
970 for(s=0;s<g->num_points;s++) {
971 ttfpoint_t*p = &g->points[s];
972 int dy = p->y - lasty;
973 if(dy>32767 || dy<-32768) {
974 msg("<error> Coordinate overflow in glyph");
977 if(dy>0 && dy<=255) writeU8(w, dy);
978 else if(dy<0 && dy>=-255) writeU8(w, -dy);
979 else if(dy) writeS16(w, dy);
983 U32* glyf_write(ttf_t* ttf, ttf_table_t*w)
985 U32*locations = malloc(sizeof(U32)*(ttf->num_glyphs+1));
987 for(t=0;t<ttf->num_glyphs;t++) {
988 locations[t] = w->len;
989 ttfglyph_t*g = &ttf->glyphs[t];
991 int num_contours = 0;
992 for(s=0;s<g->num_points;s++) {
993 if(g->points[s].flags&GLYPH_CONTOUR_END)
996 writeS16(w, num_contours?num_contours:1);
997 writeS16(w, g->xmin);
998 writeS16(w, g->ymin);
999 writeS16(w, g->xmax);
1000 writeS16(w, g->ymax);
1003 /* some ttf parsers can't deal with zero contours, so in the case
1004 of an empty glyph, write a single point (0,0) */
1005 writeU16(w, 0); //endpoint of 1st contour
1006 writeU16(w, g->code_size);
1008 writeBlock(w, g->code, g->code_size);
1009 writeU8(w, 0x31); //flag (xy=(0,0),on curve)
1011 write_simple_glyph(w, g);
1014 locations[t] = w->len;
1017 void glyf_dump(ttf_t* ttf)
1020 for(t=0;t<ttf->num_glyphs;t++) {
1021 ttfglyph_t*g = &ttf->glyphs[t];
1022 printf("glyph %d)\n", t);
1023 printf(" advance=%d\n", g->advance);
1024 printf(" bearing=%d\n", g->bearing);
1025 printf(" bbox=(%d/%d/%d/%d)\n", g->xmin, g->ymin, g->xmax, g->ymax);
1026 printf(" points=(");
1028 for(s=0;s<g->num_points;s++) {
1030 printf("%d/%d/0x%02x", g->points[s].x, g->points[s].y, g->points[s].flags);
1034 hexdump(g->code, g->code_size, " ");
1038 void glyf_delete(ttf_t* ttf)
1043 for(t=0;t<ttf->num_glyphs;t++) {
1044 if(ttf->glyphs[t].code) {
1045 free(ttf->glyphs[t].code);
1046 ttf->glyphs[t].code = 0;
1048 if(ttf->glyphs[t].points) {
1049 free(ttf->glyphs[t].points);
1050 ttf->glyphs[t].points = 0;
1053 free(ttf->glyphs);ttf->glyphs=0;
1056 static void grow_unicode(ttf_t*ttf, int index)
1060 ttf->unicode = rfx_calloc(sizeof(ttf->unicode[0])*size);
1061 } else if(ttf->unicode_size<size) {
1062 ttf->unicode = rfx_realloc(ttf->unicode, sizeof(ttf->unicode[0])*size);
1063 memset(ttf->unicode+ttf->unicode_size, 0, sizeof(ttf->unicode[0])*(size - ttf->unicode_size));
1065 ttf->unicode_size = size;
1068 void cmap_parse(memreader_t*r, ttf_t*ttf)
1070 readU16(r); // version (0)
1071 int num_subtables = readU16(r);
1073 if(r->pos+num_subtables*8 > r->size) {
1074 msg("<warning> CMap overflow");
1075 num_subtables = (r->size-r->pos)/8;
1078 for(t=0;t<num_subtables;t++) {
1079 U16 platform = readU16(r);
1080 U16 encoding = readU16(r);
1081 U32 offset = readU32(r);
1082 if(offset>r->size) {
1083 msg("<warning> CMAP table %d %d is out of bounds (%d)", platform, encoding, offset);
1087 int is_unicode = platform==0 ||
1088 platform==3 && encoding == 1 ||
1089 platform==3 && encoding == 10;
1094 INIT_READ(t, r->mem, r->size, offset);
1095 U16 format = readU16(&t);
1096 int length = readU16(&t);
1097 U16 language = readU16(&t);
1100 msg("<warning> Language code %02x in unicode mapping", language);
1105 if(t.pos+length > t.size) {
1106 msg("<warning> overflow in format 0 cmap table");
1109 data = malloc(num*sizeof(unicode_t));
1111 grow_unicode(ttf, num);
1112 for(s=0;s<num;s++) {
1113 ttf->unicode[s] = readU8(&t);
1115 } else if(format == 4) {
1116 U16 segment_count = readU16(&t);
1117 if(segment_count&1) {
1118 msg("<error> Bad segmentx2 count %d", segment_count);
1122 readU16(&t); //searchrange
1123 readU16(&t); //entry selector
1124 readU16(&t); //range shift
1125 INIT_READ(r_end, t.mem, t.size, t.pos);
1126 INIT_READ(r_start, t.mem, t.size, t.pos+2+segment_count*2);
1127 INIT_READ(r_delta, t.mem, t.size, t.pos+2+segment_count*4);
1128 INIT_READ(r_range, t.mem, t.size, t.pos+2+segment_count*6);
1129 int glyphmap_start = t.pos+2+segment_count*8;
1131 for(s=0;s<segment_count;s++) {
1132 U16 start = readU16(&r_start);
1133 U16 end = readU16(&r_end);
1134 U16 delta = readU16(&r_delta);
1135 U16 range = readU16(&r_range);
1136 if(start==0xffff && end==0xffff && delta==1) {
1137 /* this is a common occurence in fonts which explicitly map
1138 "unicode undefined" (0xffff) to "glyph undefined" (0).
1139 We don't want to blow our unicode table up to 65536 just
1140 because of this, so ignore this entry.
1144 grow_unicode(ttf, end);
1147 for(u=start;u<=end;u++) {
1148 ttf->unicode[u] = (u + delta) & 0xffff;
1151 INIT_READ(g, t.mem, t.size, r_range.pos-2+range);
1152 for(u=start;u<=end;u++) {
1153 ttf->unicode[u] = readU16(&g);
1161 static int segment_size(unicode_t*unicode, int pos, int size)
1165 for(s=pos;s<size;s++) {
1169 /* a segment costs us 8 bytes, so for more than 4 consecutive
1170 zero entries (16 bit each) in the glyph index array,
1171 it pays off to start a new segment */
1175 s -= count; // go to the last filled in entry
1181 void cmap_write(ttf_t* ttf, ttf_table_t*w)
1183 writeU16(w, 0); //version
1184 writeU16(w, 2); //two tables
1186 writeU16(w, 0); //platform (unicode)
1187 writeU16(w, 3); //encoding (unicode 2.0)
1188 writeU32(w, 20); //offset
1190 writeU16(w, 3); //platform (windows)
1191 writeU16(w, 1); //encoding (unicode basic multilingual plane UCS-2)
1192 writeU32(w, 20); //offset
1194 writeU16(w, 4); // format=4
1195 int length_pos = w->len;
1196 writeU16(w, 0); // length: we don't know yet
1197 writeU16(w, 0); // language (n/a for unicode)
1198 int num_segments_pos = w->len;
1199 writeU16(w, 0); //number of segments: we don't know yet either
1200 writeU16(w, 0); //searchrange
1201 writeU16(w, 0); //entry selector
1202 writeU16(w, 0); //range shift
1206 while(pos < ttf->unicode_size) {
1207 if(!ttf->unicode[pos]) {
1211 int s = segment_size(ttf->unicode, pos, ttf->unicode_size);
1216 int end_pos = w->len;
1217 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //end array
1218 writeU16(w, 0); //reserved byte
1219 int start_pos = w->len;
1220 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //start array
1221 int delta_pos = w->len;
1222 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //delta array
1223 int range_pos = w->len;
1224 for(t=0;t<num_segments;t++) {writeU16(w, 0);} //range array
1226 w->data[num_segments_pos]=num_segments>>8;
1227 w->data[num_segments_pos+1]=num_segments;
1231 while(pos < ttf->unicode_size) {
1232 if(!ttf->unicode[pos]) {
1236 U16 end = segment_size(ttf->unicode, pos, ttf->unicode_size);
1237 w->data[end_pos++]=end>>8;
1238 w->data[end_pos++]=end;
1239 w->data[start_pos++]=pos>>8;
1240 w->data[start_pos++]=pos;
1242 U16 delta = ttf->unicode[pos]-pos;
1244 for(s=pos+1;s<=end;s++) {
1245 U16 delta2 = ttf->unicode[pos]-pos;
1256 range = w->len - range_pos+num_segments*2;
1257 for(s=pos;s<=end;s++) {
1258 writeU16(w, ttf->unicode[s]);
1261 w->data[delta_pos++]=delta>>8;
1262 w->data[delta_pos++]=delta;
1263 w->data[range_pos++]=range>>8;
1264 w->data[range_pos++]=range;
1268 w->data[length_pos]=(w->len-20)>>8;
1269 w->data[length_pos+1]=w->len-20;
1271 void cmap_delete(ttf_t*ttf)
1277 ttf->unicode_size=0;
1280 static int ttf_parse_tables(ttf_t*ttf)
1284 table = ttf_find_table(ttf, TAG_HEAD);
1286 msg("<error> Font has no head table");
1289 INIT_READ(m, table->data, table->len, 0);
1290 int loc_index = head_parse(ttf, &m);
1291 ttf_table_delete(ttf, table);
1293 table = ttf_find_table(ttf, TAG_MAXP);
1295 msg("<error> Font has no maxp table");
1298 INIT_READ(m2, table->data, table->len, 0);
1299 ttf->maxp = maxp_parse(ttf, &m2);
1300 ttf_table_delete(ttf, table);
1302 if(!ttf->num_glyphs) {
1303 msg("<error> Invalid number of characters");
1306 ttf->glyphs = rfx_calloc(sizeof(ttfglyph_t)*ttf->num_glyphs);
1308 table = ttf_find_table(ttf, TAG_OS2);
1310 INIT_READ(m, table->data, table->len, 0);
1311 ttf->os2 = os2_parse(&m);
1312 ttf_table_delete(ttf, table);
1315 table = ttf_find_table(ttf, TAG_HHEA);
1317 INIT_READ(m, table->data, table->len, 0);
1318 int num_advances = hea_parse(&m, ttf);
1319 ttf_table_delete(ttf, table);
1321 table = ttf_find_table(ttf, TAG_HMTX);
1323 INIT_READ(m, table->data, table->len, 0);
1324 hmtx_parse(&m, ttf, num_advances);
1325 ttf_table_delete(ttf, table);
1328 table = ttf_find_table(ttf, TAG_VHEA);
1331 INIT_READ(m, table->data, table->len, 0);
1332 int num_advances = hea_parse(&m, ttf);
1333 ttf_table_delete(ttf, table);
1335 table = ttf_find_table(ttf, TAG_VMTX);
1337 INIT_READ(m, table->data, table->len, 0);
1338 hmtx_parse(&m, ttf, num_advances);
1339 ttf_table_delete(ttf, table);
1342 msg("<error> Font contains neither HHEA nor VHEA");
1345 table = ttf_find_table(ttf, TAG_LOCA);
1347 INIT_READ(m, table->data, table->len, 0);
1348 U32*loca = loca_parse(&m, ttf, loc_index);
1349 ttf_table_delete(ttf, table);
1350 table = ttf_find_table(ttf, TAG_GLYF);
1352 INIT_READ(m, table->data, table->len, 0);
1353 glyf_parse(&m, ttf, loca);
1354 ttf_table_delete(ttf, table);
1359 table = ttf_find_table(ttf, TAG_CMAP);
1361 INIT_READ(m, table->data, table->len, 0);
1362 cmap_parse(&m, ttf);
1363 ttf_table_delete(ttf, table);
1368 static void ttf_collapse_tables(ttf_t*ttf)
1372 table = ttf_addtable(ttf, TAG_MAXP);
1373 maxp_write(ttf, table);
1376 table = ttf_addtable(ttf, TAG_OS2);
1377 os2_write(ttf, table);
1380 if(!ttf->is_vertical) {
1381 table = ttf_addtable(ttf, TAG_HMTX);
1382 int num_advances = mtx_write(ttf, table);
1383 table = ttf_addtable(ttf, TAG_HHEA);
1384 hea_write(ttf, table, num_advances);
1386 table = ttf_addtable(ttf, TAG_VMTX);
1387 int num_advances = mtx_write(ttf, table);
1388 table = ttf_addtable(ttf, TAG_VHEA);
1389 hea_write(ttf, table, num_advances);
1393 if(ttf->num_glyphs) {
1394 table = ttf_addtable(ttf, TAG_CMAP);
1395 cmap_write(ttf, table);
1398 table = ttf_addtable(ttf, TAG_GLYF);
1399 U32*locations = glyf_write(ttf, table);
1402 table = ttf_addtable(ttf, TAG_LOCA);
1403 loca_size = loca_write(ttf, table, locations);
1407 table = ttf_addtable(ttf, TAG_HEAD);
1408 head_write(ttf, table, loca_size);
1412 ttf_t* load_ttf(void*data, int length)
1414 INIT_READ(r,data,length, 0);
1417 msg("<error> Truncated Truetype file (%d bytes)", length);
1421 ttf_t*ttf = rfx_calloc(sizeof(ttf_t));
1422 ttf->version = readU32(&r);
1423 if(ttf->version == TTCFTAG) {
1424 /* a ttc collection is a number of truetype fonts
1425 packaged together */
1427 msg("<error> Truncated TTC file (%d bytes)", length);
1430 U32 ttcf_version = readU32(&r); // 0x00000100: v1.0, 0x00000200: v2.0, includes DSIG table
1431 U32 num_fonts = readU32(&r); // number of fonts
1432 U32 font1_position = readU32(&r);
1433 if(font1_position+12 > length) {\
1434 msg("<error> Truncated TTC file (%d bytes, first font at %d)", length, font1_position);
1437 r.pos = font1_position;
1438 ttf->version = readU32(&r);
1441 int num_tables = readU16(&r);
1443 readU16(&r); //search range
1444 readU16(&r); //entry selector
1445 readU16(&r); //range shift
1447 if(num_tables*16 > length) {
1448 msg("<error> Truncated TTC file (table entries: %d)", num_tables);
1449 if(ttf->version != OPENTYPE &&
1450 ttf->version != TRUETYPE_MACOS &&
1451 ttf->version != VERSION_1_0) {
1452 // bad table length, weird version. This is probably not a ttf file.
1457 U32*table_data = malloc(16*num_tables);
1459 for(t=0;t<num_tables*4;t++) {
1460 table_data[t] = readU32(&r);
1462 for(t=0;t<num_tables;t++) {
1463 U32 tag = table_data[t*4];
1464 U32 checksum = table_data[t*4+1];
1465 U32 pos = table_data[t*4+2];
1466 U32 len = table_data[t*4+3];
1468 if(pos+len > length) {
1469 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);
1471 U8*mem = malloc(len);
1473 readBlock(&r, mem, len);
1475 ttf_table_t*table = ttf_addtable(ttf, tag);
1477 table->len = table->memsize = len;
1479 U32 checksum2 = ttf_table_checksum(table);
1480 if(checksum2!=checksum) {
1481 msg("<warning> Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x",
1482 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1483 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1484 len, checksum2, checksum);
1491 if(!ttf_parse_tables(ttf))
1497 ttf_table_t* ttf_write(ttf_t*ttf)
1499 ttf_collapse_tables(ttf);
1501 ttf_table_t*file = ttf_table_new(0);
1502 writeU32(file, VERSION_1_0);
1504 /* write number of tables */
1506 ttf_table_t*t = ttf->tables;
1511 writeU16(file, num_tables);
1513 /* write search range */
1514 int tmp = num_tables;
1515 int search_range = 0;
1522 writeU16(file, search_range);
1524 /* write entry selector */
1525 int entry_selector = 0;
1530 writeU16(file, entry_selector);
1532 /* write range shift */
1533 int range_shift = num_tables*16 - search_range;
1534 writeU16(file, range_shift);
1536 /* write table dictionary */
1537 int table_dictionary_pos = file->len;
1538 int data_pos = file->len + num_tables*16;
1539 for(t=ttf->tables;t;t=t->next) {
1540 writeU32(file, t->id);
1541 writeU32(file, ttf_table_checksum(t));
1542 writeU32(file, data_pos);
1543 writeU32(file, t->len);
1545 data_pos += (-t->len)&3; //pad
1550 U8 zero[4]={0,0,0,0};
1551 for(t=ttf->tables;t;t=t->next) {
1552 if(t->id == TAG_HEAD)
1553 head_pos = file->len;
1554 writeBlock(file, t->data, t->len);
1555 writeBlock(file, zero, (-t->len)&3); //pad
1557 U32 checksum = 0xb1b0afba - ttf_table_checksum(file);
1558 U8*checksum2 = file->data + head_pos + 8;
1559 checksum2[0] = checksum>>24;
1560 checksum2[1] = checksum>>16;
1561 checksum2[2] = checksum>>8;
1562 checksum2[3] = checksum>>0;
1566 void ttf_save(ttf_t*ttf, const char*filename)
1568 ttf_table_t* t = ttf_write(ttf);
1569 FILE*fi = fopen(filename, "wb");
1574 fwrite(t->data, t->len, 1, fi);
1576 ttf_table_delete(0, t);
1579 void ttf_dump(ttf_t*ttf)
1581 msg("<notice> Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":"");
1582 ttf_table_t*table = ttf->tables;
1584 U32 tag = table->id;
1585 msg("<notice> Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)",
1586 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff,
1587 (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len);
1588 table = table->next;
1590 //ttf_table_dump(ttf_find_table(ttf, TAG_MAXP));
1598 void ttf_destroy(ttf_t*ttf)
1600 ttf_table_t*table = ttf->tables;
1602 ttf_table_t*next = table->next;
1616 int main(int argn, const char*argv[])
1618 setConsoleLogging(7);
1619 const char*filename = "comic.ttf";
1622 //msg("<notice> Loading %s", filename);
1623 memfile_t*m = memfile_open(filename);
1624 ttf_t*ttf = load_ttf(m->data, m->len);
1628 //printf("os2 version: %04x (%d), maxp size: %d\n",
1629 // ttf->os2->version, ttf->os2->size, ttf->maxp->size);
1630 ttf_save(ttf, "comic2.ttf");