X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=blobdiff_plain;f=lib%2Fttf.c;h=c1fd06db7be04816483718cfe5020d941697c6c8;hp=a5bcfe4483901118414631c7756a74046a82efd9;hb=fc8854e5ed42dbcef96d25eb851b9873707a15ff;hpb=114fd977a15dcc7a9b52700279576cba80e6dc09 diff --git a/lib/ttf.c b/lib/ttf.c index a5bcfe4..c1fd06d 100644 --- a/lib/ttf.c +++ b/lib/ttf.c @@ -49,13 +49,11 @@ #define TAG_NAME 0x6e616d65 #define TAG_POST 0x706f7374 #define TAG_CFF 0x43464620 //required for opentype +#define TAG_CVT 0x63767420 +#define TAG_FPGM 0x6670676d +#define TAG_GASP 0x67617370 +#define TAG_PREP 0x70726570 -/* TODO: - fpgm - assembly instructions - prep - assembly instructions - cvt - constant value table - gasp - gridfitting procedure -*/ static U32 checksum_block(U8*_data, int len) { @@ -118,7 +116,7 @@ static void readBlock(memreader_t*r, void*dest, int len) r->pos += len; } } -static void reader_reset(memreader_t*r) +static void reader_reset(memreader_t*r) { r->pos; } @@ -200,7 +198,7 @@ ttf_table_t*ttf_addtable(ttf_t*ttf, U32 id) before->len = 0; return before; } - + if(!after) { t->next = ttf->tables; ttf->tables = t; @@ -217,7 +215,7 @@ ttf_table_t*ttf_find_table(ttf_t*ttf, U32 id) { ttf_table_t*table = ttf->tables; while(table) { - if(table->id == id) + if(table->id == id) return table; table = table->next; } @@ -228,9 +226,9 @@ void ttf_table_delete(ttf_t*ttf, ttf_table_t*table) if(ttf && ttf->tables == table) { ttf->tables = table->next; } - if(table->prev) + if(table->prev) table->prev->next = table->next; - if(table->next) + if(table->next) table->next->prev = table->prev; free(table->data); free(table); @@ -305,12 +303,12 @@ static int head_parse(ttf_t*ttf, memreader_t*r) { ttf->head = rfx_calloc(sizeof(table_head_t)); U32 version = readU32(r); - if(version!=VERSION_1_0) + if(version!=VERSION_1_0) msg(" Font HEAD has unknown version %08x", version); U32 revision = readU32(r); U32 checksum2 = readU32(r); U32 magic = readU32(r); - if(magic!=0x5f0f3cf5) + if(magic!=0x5f0f3cf5) msg(" Font HEAD has unknown magic number %08x", magic); ttf->head->flags = readU16(r); ttf->head->units_per_em = readU16(r); @@ -389,7 +387,7 @@ static table_os2_t*os2_new(ttf_t*ttf) /* that's what everybody seems to fill in */ os2->usWeightClass = 400; os2->usWidthClass = 5; - + if(ttf->head) { int advance = (ttf->head->xmax - ttf->head->xmin)/2; int height = (ttf->head->xmax - ttf->head->xmin); @@ -405,8 +403,8 @@ static table_os2_t*os2_new(ttf_t*ttf) os2->ySuperscriptYOffset = (ttf->head->ymax - ttf->head->ymin)/2; os2->yStrikeoutSize = ttf->head->units_per_em / 10; os2->yStrikeoutPosition = ymid; - os2->usWinAscent = ttf->head->ymax; - os2->usWinDescent = ttf->head->ymin<0?0:ttf->head->ymin; + os2->usWinAscent = ttf->ascent; + os2->usWinDescent = ttf->descent>0?0:-ttf->descent; os2->sxHeight = ymid; os2->sCapHeight = height*2/3; } @@ -498,7 +496,7 @@ static table_os2_t*os2_parse(memreader_t*r) os2->usDefaultChar = readU16(r); os2->usBreakChar = readU16(r); os2->usMaxContext = readU16(r); - + if(r->pos < r->size) { msg(" Leftover bytes (%d) in OS2 tag", r->size - r->pos); } @@ -640,13 +638,14 @@ static table_maxp_t*maxp_new(ttf_t*ttf) maxp->maxComponentPoints = 0; maxp->maxComponentContours = 0; } + maxp->maxZones = 2; // we don't use the Z0 zone return maxp; } static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r) { U32 version = readU32(r); ttf->num_glyphs = readU16(r); - /* according to freetype, older fonts (version<0x10000) + /* according to freetype, older fonts (version<0x10000) apparently only contain the number of glyphs. this is rather rare, though. */ if(version<0x10000 && r->size==6) return 0; @@ -728,15 +727,15 @@ static table_hea_t*hea_new(ttf_t*ttf) for(t=0;tnum_glyphs;t++) { if(ttf->glyphs[t].advance > hea->advanceWidthMax) hea->advanceWidthMax = ttf->glyphs[t].advance; - if(ttf->glyphs[t].xmin < hea->minLeftSideBearing) - hea->minLeftSideBearing = ttf->glyphs[t].xmin; + if(ttf->glyphs[t].bearing < hea->minLeftSideBearing) + hea->minLeftSideBearing = ttf->glyphs[t].bearing; if(ttf->glyphs[t].xmax < hea->minRightSideBearing) hea->minRightSideBearing = ttf->glyphs[t].xmax; int width = ttf->glyphs[t].xmax - ttf->glyphs[t].xmin; if(width > hea->xMaxExtent) hea->xMaxExtent = width; } - /* TODO: caret */ + hea->caretSlopeRise = 1; } return hea; } @@ -830,7 +829,7 @@ static void mtx_parse(memreader_t*r, ttf_t*ttf, int num_advances) rest = ttf->num_glyphs-num_advances; } for(t=0;tglyphs[t].advance = old_advance; + ttf->glyphs[t].advance = old_advance; ttf->glyphs[t].bearing = readS16(r); } } @@ -851,10 +850,10 @@ static int mtx_write(ttf_t*ttf, ttf_table_t*w) int t; for(t=0;tglyphs[t].advance); - writeU16(w, ttf->glyphs[t].bearing); + writeS16(w, ttf->glyphs[t].bearing); } for(;tnum_glyphs;t++) { - writeU16(w, ttf->glyphs[t].bearing); + writeS16(w, ttf->glyphs[t].bearing); } return num_advances; } @@ -950,15 +949,15 @@ static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int gl glyph->code_size = code_len; } - if(!endpoints) + if(!endpoints) return 1; - /*msg(" TTF Glyph %d) code_size=%d num_contours=%d glyph->num_points=%d %d/%d/%d/%d", + /*msg(" TTF Glyph %d) code_size=%d num_contours=%d glyph->num_points=%d %d/%d/%d/%d", glyphnr, code_len, num_contours, glyph->num_points, xmin, ymin, xmax, ymax);*/ INIT_READ(fx, r->mem, r->size, r->pos); INIT_READ(fy, r->mem, r->size, r->pos); - + glyph->num_points = endpoints[num_contours-1] + 1; glyph->points = rfx_calloc(sizeof(ttfpoint_t)*glyph->num_points); @@ -974,7 +973,7 @@ static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int gl return 0; } int count = 1; - if(flag & 0x08) + if(flag & 0x08) count += readU8(r); if(count+num>glyph->num_points) { msg(" Bad count (%d) in glyph (%d) (at pos %d)", count, glyphnr, num); @@ -1003,7 +1002,7 @@ static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int gl if((flag&0x12) == 0x12) x += readU8(r); else if((flag&0x12) == 0x02) x -= readU8(r); else if((flag&0x12) == 0x00) x += readS16(r); - + glyph->points[num].x = x; U8 f = flag&GLYPH_ON_CURVE; if(is_start) f|=GLYPH_CONTOUR_START; @@ -1013,7 +1012,7 @@ static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int gl is_start = is_end; } while(--count); } - + /* parse flag array (3rd pass) and y coordinates */ num=0; int y = 0; @@ -1041,7 +1040,7 @@ static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca) if(loca[t]==loca[t+1] || loca[t]==r.size) continue; //empty glyph if(r.pos+10>r.size) { - msg(" Truncated glyph entry %d/%d (or bad loca entry %d/%d, next loca: %d)", + msg(" Truncated glyph entry %d/%d (or bad loca entry %d/%d, next loca: %d)", t, ttf->num_glyphs, loca[t], r.size, loca[t+1]); break; } @@ -1050,7 +1049,7 @@ static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca) ttf->glyphs[t].ymin = readS16(&r); ttf->glyphs[t].xmax = readS16(&r); ttf->glyphs[t].ymax = readS16(&r); - + if(num_contours<0) { if(warn_about_compound_glyphs) msg(" Compound glyphs not supported yet"); @@ -1070,7 +1069,7 @@ void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g) if(g->points[s].flags&GLYPH_CONTOUR_END) writeU16(w, s); } - + /* bytecode */ writeU16(w, g->code_size); if(g->code_size) @@ -1171,7 +1170,7 @@ U32* glyf_write(ttf_t* ttf, ttf_table_t*w) writeS16(w, g->ymin); writeS16(w, g->xmax); writeS16(w, g->ymax); - + if(!num_contours) { /* some ttf parsers can't deal with zero contours, so in the case of an empty glyph, write a single point (0,0) */ @@ -1204,13 +1203,13 @@ void glyf_dump(ttf_t* ttf) printf("%d/%d/0x%02x", g->points[s].x, g->points[s].y, g->points[s].flags); } printf(")\n"); - if(g->code_size) + if(g->code_size) hexdump(g->code, g->code_size, " "); } } void glyf_delete(ttf_t* ttf) { - if(!ttf->glyphs) + if(!ttf->glyphs) return; int t; for(t=0;tnum_glyphs;t++) { @@ -1261,7 +1260,7 @@ void cmap_parse(memreader_t*r, ttf_t*ttf) platform==3 && encoding == 1 || platform==3 && encoding == 10; - if(!is_unicode) + if(!is_unicode) continue; INIT_READ(t, r->mem, r->size, offset); @@ -1286,7 +1285,7 @@ void cmap_parse(memreader_t*r, ttf_t*ttf) ttf->unicode[s] = readU8(&t); } } else if(format == 4) { - U16 segment_count = readU16(&t); + U16 segment_count = readU16(&t); if(segment_count&1) { msg(" Bad segmentx2 count %d", segment_count); continue; @@ -1308,8 +1307,8 @@ void cmap_parse(memreader_t*r, ttf_t*ttf) U16 delta = readU16(&r_delta); U16 range = readU16(&r_range); if(start==0xffff && end==0xffff && delta==1) { - /* this is a common (maybe even required) occurence in fonts - which explicitly map "unicode undefined" (0xffff) to + /* this is a common (maybe even required) occurence in fonts + which explicitly map "unicode undefined" (0xffff) to "glyph undefined" (0). We don't want to blow our unicode table up to 65536 just because of this, so ignore this entry. @@ -1345,7 +1344,7 @@ static int segment_size(unicode_t*unicode, int pos, int size) if(!unicode[s]) count++; if(count>4) { - /* a segment costs us 8 bytes, so for more than 4 consecutive + /* a segment costs us 8 bytes, so for more than 4 consecutive zero entries (16 bit each) in the glyph index array, it pays off to start a new segment */ break; @@ -1394,7 +1393,7 @@ void cmap_write(ttf_t* ttf, ttf_table_t*w) num_segments++; // account for 0xffff mapping int glyphmap_start = w->len+2+num_segments*8; - + int t; int end_pos = w->len; for(t=0;tlen; for(t=0;tdata[num_segments_pos]=(num_segments*2)>>8; - w->data[num_segments_pos+1]=(num_segments*2); - + + /* backpatch number of segments */ + w->data[num_segments_pos++]=(num_segments*2)>>8; + w->data[num_segments_pos++]=(num_segments*2); + /* backpatch search range */ + int tmp = num_segments; + int search_range = 0; + while(tmp) { + search_range = tmp; + tmp = tmp&(tmp-1); + } + w->data[num_segments_pos++]=(search_range*2)>>8; + w->data[num_segments_pos++]=(search_range*2); + /* backpatch entry selector */ + int entry_selector = 0; + tmp = search_range; + while(tmp>1) {tmp>>=1;entry_selector++;} + w->data[num_segments_pos++]=entry_selector>>8; + w->data[num_segments_pos++]=entry_selector; + /* backpatch range shift */ + int range_shift = num_segments*2 - search_range*2; + w->data[num_segments_pos++]=range_shift>>8; + w->data[num_segments_pos++]=range_shift; + pos=0; num_segments = 0; while(pos < ttf->unicode_size) { @@ -1483,7 +1502,7 @@ void name_parse(memreader_t*r, ttf_t*ttf) U16 format = readU16(r); U16 count = readU16(r); U16 offset = readU16(r); - + int t; for(t=0;tmem, r->size, offset+offset_2); if(!(platform==0 || (platform==1 && encoding==0))) continue; INIT_READ(s, r->mem, r->size, offset+offset_2); - if(name_id==1) { - if(ttf->family_name) free(ttf->family_name); - ttf->family_name = readString(&s, len); - } - if(name_id==2) { - if(ttf->subfamily_name) free(ttf->subfamily_name); - ttf->subfamily_name = readString(&s, len); + switch (name_id) { + case 1: read_name = &ttf->family_name; break; + case 2: read_name = &ttf->subfamily_name; break; + case 3: read_name = &ttf->font_uid; break; + case 4: read_name = &ttf->full_name; break; + case 5: read_name = &ttf->version_string; break; + case 6: read_name = &ttf->postscript_name; break; + default: read_name = 0; } - if(name_id==3) { - if(ttf->version_string) free(ttf->version_string); - ttf->version_string = readString(&s, len); - } - if(name_id==4) { - if(ttf->full_name) free(ttf->full_name); - ttf->full_name = readString(&s, len); + + if (read_name) { + if (*read_name) free(*read_name); + *read_name = readString(&s, len); } } } void name_write(ttf_t*ttf, ttf_table_t*table) { - char*strings[4] = {ttf->full_name, ttf->family_name, ttf->subfamily_name, ttf->version_string}; - int codes[4] = {4,1,2,3}; + char*strings[6] = {ttf->family_name, ttf->subfamily_name, ttf->font_uid, ttf->full_name, ttf->version_string, ttf->postscript_name}; + int codes[6] = {1,2,3,4,5,6}; writeU16(table, 0); //format int count = 0; int t; int nr = sizeof(strings)/sizeof(strings[0]); - + for(t=0;tlen; writeU16(table, 0); //offset (will be filled in later) + /* Windows expects the name table to be sorted by platform/encoding/language/name_id */ int offset = 0; - for(t=0;tdata[offset_pos] = table->len>>8; table->data[offset_pos+1] = table->len; - for(t=0;tversion_string); ttf->version_string=0; } + if(ttf->font_uid) { + free(ttf->font_uid); + ttf->font_uid=0; + } + if(ttf->postscript_name) { + free(ttf->postscript_name); + ttf->postscript_name=0; + } } static table_post_t*post_new(ttf_t*ttf) @@ -1587,15 +1638,15 @@ static table_post_t*post_new(ttf_t*ttf) void post_parse(memreader_t*r, ttf_t*ttf) { table_post_t*post = ttf->post = rfx_calloc(sizeof(table_post_t)); - U16 format = readU16(r); - post->italic_angle = readU16(r); + U32 format = readU32(r); + post->italic_angle = readU32(r); post->underline_position = readU16(r); post->underline_thickness = readU16(r); - U16 is_monospaced = readU16(r); - readU16(r); // min mem 42 - readU16(r); - readU16(r); // min mem 1 - readU16(r); + U16 is_monospaced = readU32(r); + readU32(r); // min mem 42 + readU32(r); + readU32(r); // min mem 1 + readU32(r); } void post_write(ttf_t*ttf, ttf_table_t*table) { @@ -1618,6 +1669,152 @@ void post_delete(ttf_t*ttf) } } +void cvt_parse(memreader_t*r, ttf_t*ttf) +{ + table_cvt_t*cvt = ttf->cvt = rfx_calloc(sizeof(table_cvt_t)); + cvt->num = r->size/2; + cvt->values = malloc(cvt->num*sizeof(S16)); + int t; + for(t=0;tnum;t++) { + cvt->values[t] = readS16(r); + } +} +void cvt_write(ttf_t*ttf, ttf_table_t*table) +{ + table_cvt_t*cvt = ttf->cvt; + int t; + for(t=0;tnum;t++) { + writeS16(table, cvt->values[t]); + } +} +void cvt_delete(ttf_t*ttf) +{ + if(ttf->cvt) { + if(ttf->cvt->values) + free(ttf->cvt->values); + free(ttf->cvt); + ttf->cvt = 0; + } +} + +static table_gasp_t*gasp_new(ttf_t*ttf) +{ + table_gasp_t*gasp = rfx_calloc(sizeof(table_gasp_t)); + gasp->num = 1; + gasp->records = rfx_calloc(sizeof(gasp->records[0])*gasp->num); + + gasp->records[0].size = 65535; + gasp->records[0].behaviour = 15; //gridfit+grayscale rendering + return gasp; +} +void gasp_parse(memreader_t*r, ttf_t*ttf) +{ + table_gasp_t*gasp = ttf->gasp = rfx_calloc(sizeof(table_gasp_t)); + readU16(r); //version + int num = readU16(r); + int t; + if(!num) return; + gasp->records = malloc(sizeof(gasp->records[0])*num); + for(t=0;trecords[t].size = readU16(r); + gasp->records[t].behaviour = readU16(r); + } +} + +#define GASP_SYMMETRIC_GRIDFIT 0x0008 +#define GASP_SYMMETRIC_SMOOTHING 0x0004 +#define GASP_DOGRAY 0x0002 +#define GASP_GRIDFIT 0x0001 + +void gasp_write(ttf_t*ttf, ttf_table_t*table) +{ + table_gasp_t*gasp = ttf->gasp; + int version = 0; + int t; + for(t=0;tnum;t++) { + if(gasp->records[t].behaviour & ~(GASP_GRIDFIT | GASP_DOGRAY)) { + version = 1; + } + } + writeU16(table, version); + writeU16(table, gasp->num); + for(t=0;tnum;t++) { + writeU16(table, gasp->records[t].size); + writeU16(table, gasp->records[t].behaviour); + } +} +void gasp_delete(ttf_t*ttf) +{ + if(ttf->gasp) { + if(ttf->gasp->records) + free(ttf->gasp->records); + free(ttf->gasp); + ttf->gasp = 0; + } +} + +table_code_t*prep_new(ttf_t*ttf) +{ + table_code_t*prep = ttf->prep = rfx_calloc(sizeof(table_code_t)); + ttf_table_t*t = ttf_table_new(0); + writeU8(t,0xb8);writeU16(t,0x1ff); // pushword(0x1ff) + writeU8(t,0x85); //scanctrl (always do dropout, for all sizes) + writeU8(t,0xb0);writeU8(t,1); // pushbyte(1) + writeU8(t,0x8d); //scantype (simple dropout control w/o stubs) + writeU8(t,0xb0);writeU8(t,5); // pushbyte(5) + writeU8(t,0x8d); //scantype (for windows) smart dropout control w/o stubs + prep->code = t->data; + prep->size = t->len; + free(t); + return prep; + +} +void fpgm_parse(memreader_t*r, ttf_t*ttf) +{ + table_code_t*fpgm = ttf->fpgm = rfx_calloc(sizeof(table_code_t)); + if(!r->size) return; + fpgm->size = r->size; + fpgm->code = malloc(r->size); + readBlock(r, fpgm->code, r->size); +} +void fpgm_write(ttf_t*ttf, ttf_table_t*table) +{ + table_code_t*code = ttf->fpgm; + writeBlock(table, code->code, code->size); +} +void fpgm_delete(ttf_t*ttf) +{ + if(ttf->fpgm) { + if(ttf->fpgm->code) + free(ttf->fpgm->code); + free(ttf->fpgm); + ttf->fpgm = 0; + } +} + +void prep_parse(memreader_t*r, ttf_t*ttf) +{ + table_code_t*prep = ttf->prep = rfx_calloc(sizeof(table_code_t)); + if(!r->size) return; + prep->size = r->size; + prep->code = malloc(r->size); + readBlock(r, prep->code, r->size); +} +void prep_write(ttf_t*ttf, ttf_table_t*table) +{ + table_code_t*code = ttf->prep; + writeBlock(table, code->code, code->size); +} +void prep_delete(ttf_t*ttf) +{ + if(ttf->prep) { + if(ttf->prep->code) + free(ttf->prep->code); + free(ttf->prep); + ttf->prep = 0; + } +} + static int ttf_parse_tables(ttf_t*ttf) { ttf_table_t*table; @@ -1630,7 +1827,7 @@ static int ttf_parse_tables(ttf_t*ttf) INIT_READ(m, table->data, table->len, 0); int loc_index = head_parse(ttf, &m); ttf_table_delete(ttf, table); - + table = ttf_find_table(ttf, TAG_MAXP); if(!table) { msg(" Font has no maxp table"); @@ -1639,7 +1836,7 @@ static int ttf_parse_tables(ttf_t*ttf) INIT_READ(m2, table->data, table->len, 0); ttf->maxp = maxp_parse(ttf, &m2); ttf_table_delete(ttf, table); - + if(!ttf->num_glyphs) { msg(" Invalid number of characters"); return 0; @@ -1653,12 +1850,13 @@ static int ttf_parse_tables(ttf_t*ttf) ttf_table_delete(ttf, table); } + table = ttf_find_table(ttf, TAG_HHEA); if(table) { INIT_READ(m, table->data, table->len, 0); int num_advances = hea_parse(&m, ttf); ttf_table_delete(ttf, table); - + table = ttf_find_table(ttf, TAG_HMTX); if(table) { INIT_READ(m, table->data, table->len, 0); @@ -1696,14 +1894,21 @@ static int ttf_parse_tables(ttf_t*ttf) } free(loca); } - + table = ttf_find_table(ttf, TAG_CMAP); if(table) { INIT_READ(m, table->data, table->len, 0); cmap_parse(&m, ttf); ttf_table_delete(ttf, table); } - + + table = ttf_find_table(ttf, TAG_POST); + if(table) { + INIT_READ(m, table->data, table->len, 0); + post_parse(&m, ttf); + ttf_table_delete(ttf, table); + } + table = ttf_find_table(ttf, TAG_NAME); if(table) { INIT_READ(m, table->data, table->len, 0); @@ -1711,10 +1916,31 @@ static int ttf_parse_tables(ttf_t*ttf) ttf_table_delete(ttf, table); } - table = ttf_find_table(ttf, TAG_POST); + table = ttf_find_table(ttf, TAG_CVT); if(table) { INIT_READ(m, table->data, table->len, 0); - post_parse(&m, ttf); + cvt_parse(&m, ttf); + ttf_table_delete(ttf, table); + } + + table = ttf_find_table(ttf, TAG_GASP); + if(table) { + INIT_READ(m, table->data, table->len, 0); + gasp_parse(&m, ttf); + ttf_table_delete(ttf, table); + } + + table = ttf_find_table(ttf, TAG_PREP); + if(table) { + INIT_READ(m, table->data, table->len, 0); + prep_parse(&m, ttf); + ttf_table_delete(ttf, table); + } + + table = ttf_find_table(ttf, TAG_FPGM); + if(table) { + INIT_READ(m, table->data, table->len, 0); + fpgm_parse(&m, ttf); ttf_table_delete(ttf, table); } @@ -1723,11 +1949,11 @@ static int ttf_parse_tables(ttf_t*ttf) static void ttf_collapse_tables(ttf_t*ttf) { ttf_table_t*table; - + ttf_table_t*head = ttf_find_table(ttf, TAG_HEAD); - if(head) + if(head) return; //already collapsed - + if(ttf->maxp) { table = ttf_addtable(ttf, TAG_MAXP); maxp_write(ttf, table); @@ -1755,7 +1981,7 @@ static void ttf_collapse_tables(ttf_t*ttf) hea_delete(ttf); } } - + int loca_size=0; if(ttf->num_glyphs) { if(ttf->unicode) { @@ -1774,7 +2000,7 @@ static void ttf_collapse_tables(ttf_t*ttf) } } - if(ttf->full_name || ttf->family_name || ttf->subfamily_name) { + if(ttf->full_name || ttf->family_name || ttf->subfamily_name || ttf->font_uid || ttf->postscript_name) { table = ttf_addtable(ttf, TAG_NAME); name_write(ttf, table); name_delete(ttf); @@ -1784,7 +2010,27 @@ static void ttf_collapse_tables(ttf_t*ttf) post_write(ttf, table); post_delete(ttf); } - + if(ttf->cvt) { + table = ttf_addtable(ttf, TAG_CVT); + cvt_write(ttf, table); + cvt_delete(ttf); + } + if(ttf->gasp) { + table = ttf_addtable(ttf, TAG_GASP); + gasp_write(ttf, table); + gasp_delete(ttf); + } + if(ttf->fpgm) { + table = ttf_addtable(ttf, TAG_FPGM); + fpgm_write(ttf, table); + fpgm_delete(ttf); + } + if(ttf->prep) { + table = ttf_addtable(ttf, TAG_PREP); + prep_write(ttf, table); + prep_delete(ttf); + } + table = ttf_addtable(ttf, TAG_HEAD); head_write(ttf, table, loca_size); head_delete(ttf); @@ -1811,7 +2057,7 @@ ttf_t* ttf_load(void*data, int length) U32 fontDataSize = readU32(&r); U32 version = readU32(&r); U32 flags = readU32(&r); - U8 panose[10]; + U8 panose[10]; readBlock(&r, panose, 10); readU8(&r); //charset readU8(&r); //italoc @@ -1880,17 +2126,17 @@ ttf_t* ttf_load(void*data, int length) r.pos = font1_position; ttf->version = readU32(&r); } - + int num_tables = readU16(&r); - + readU16(&r); //search range readU16(&r); //entry selector readU16(&r); //range shift if(num_tables*16 > length) { msg(" Truncated TTF file (table entries: %d)", num_tables); - if(ttf->version != OPENTYPE && - ttf->version != TRUETYPE_MACOS && + if(ttf->version != OPENTYPE && + ttf->version != TRUETYPE_MACOS && ttf->version != VERSION_1_0) { // bad table length, weird version. This is probably not a ttf file. return 0; @@ -1907,21 +2153,21 @@ ttf_t* ttf_load(void*data, int length) U32 checksum = table_data[t*4+1]; U32 pos = table_data[t*4+2]; U32 len = table_data[t*4+3]; - + if(pos+len > length) { msg(" TTF Table %02x%02x%02x%02x outside of stream (pos %d)", (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, pos); } else { U8*mem = malloc(len); r.pos = pos; readBlock(&r, mem, len); - + ttf_table_t*table = ttf_addtable(ttf, tag); table->data = mem; table->len = table->memsize = len; #if 0 U32 checksum2 = ttf_table_checksum(table); if(checksum2!=checksum) { - msg(" Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x", + msg(" Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x", (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, len, checksum2, checksum); @@ -1931,16 +2177,16 @@ ttf_t* ttf_load(void*data, int length) } free(table_data); - if(!ttf_parse_tables(ttf)) + if(!ttf_parse_tables(ttf)) return 0; return ttf; } void ttf_create_truetype_tables(ttf_t*ttf) { - if(!ttf->head) + if(!ttf->head) ttf->head = head_new(ttf); - if(!ttf->maxp) + if(!ttf->maxp) ttf->maxp = maxp_new(ttf); if(!ttf->hea) ttf->hea = hea_new(ttf); @@ -1948,12 +2194,16 @@ void ttf_create_truetype_tables(ttf_t*ttf) ttf->os2 = os2_new(ttf); if(!ttf->post) ttf->post = post_new(ttf); + if(!ttf->gasp) + ttf->gasp = gasp_new(ttf); + if(!ttf->prep) + ttf->prep = prep_new(ttf); } ttf_table_t* ttf_write(ttf_t*ttf, U32*checksum_adjust) { ttf_collapse_tables(ttf); - + ttf_table_t*file = ttf_table_new(0); writeU32(file, VERSION_1_0); @@ -1965,7 +2215,7 @@ ttf_table_t* ttf_write(ttf_t*ttf, U32*checksum_adjust) t = t->next; } writeU16(file, num_tables); - + /* write search range */ int tmp = num_tables; int search_range = 0; @@ -2056,42 +2306,24 @@ ttf_table_t* ttf_eot_head(ttf_t*ttf) writeU32(file, 0); //reserved[3] writeU16(file, 0); //padding(1) - int t,len; + int i,t,len; - //family name - len = strlen(ttf->family_name); - writeU16_LE(file, len*2); - for(t=0;tfamily_name[t]); - } - writeU16(file, 0); //zero byte pad + char* strings[] = {ttf->family_name, ttf->subfamily_name, ttf->version_string, ttf->full_name}; + int nr = sizeof(strings)/sizeof(strings[0]); - //subfamily name - len = strlen(ttf->subfamily_name); - writeU16_LE(file, len*2); - for(t=0;tsubfamily_name[t]); - } - writeU16(file, 0); //zero byte pad + for(i=0;iversion_string); - writeU16_LE(file, len*2); //len - for(t=0;tversion_string[t]); + //family name + len = strlen(string); + writeU16_LE(file, len*2); + for(t=0;tfull_name); - writeU16_LE(file, len*2); //len - for(t=0;tfull_name[t]); - } writeU16(file, 0); //zero byte pad writeU16(file, 0); //padding(2) @@ -2110,7 +2342,7 @@ void ttf_save_eot(ttf_t*ttf, const char*filename) len_data[1] = full_len>>8; len_data[2] = full_len>>16; len_data[3] = full_len>>24; - + U8*len_data2 = eot->data+4; len_data2[0] = t->len>>0; len_data2[1] = t->len>>8; @@ -2155,8 +2387,8 @@ void ttf_dump(ttf_t*ttf) ttf_table_t*table = ttf->tables; while(table) { U32 tag = table->id; - msg(" Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)", - (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, + msg(" Tag %02x%02x%02x%02x [%c%c%c%c] (length: %d)", + (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, table->len); table = table->next; } @@ -2192,6 +2424,7 @@ void ttf_destroy(ttf_t*ttf) hea_delete(ttf); glyf_delete(ttf); post_delete(ttf); + cvt_delete(ttf); name_delete(ttf); free(ttf); } @@ -2201,26 +2434,24 @@ int main(int argn, const char*argv[]) { setConsoleLogging(7); const char*filename = "comic.ttf"; - if(argn>1) + if(argn>1) filename = argv[1]; //msg(" Loading %s", filename); memfile_t*m = memfile_open(filename); ttf_t*ttf = ttf_load(m->data, m->len); + if(!ttf) { msg(" Couldn't load %s", filename); return 1; } ttf_reduce(ttf); - - ttf->full_name = strdup("Test-Normal"); - ttf->family_name = strdup("Test"); - ttf->subfamily_name = strdup("Normal"); - ttf->version_string = strdup("Version 1.0"); + + ttf_create_truetype_tables(ttf); if(!ttf) return 1; memfile_close(m); //ttf_dump(ttf); - //printf("os2 version: %04x (%d), maxp size: %d\n", + //printf("os2 version: %04x (%d), maxp size: %d\n", // ttf->os2->version, ttf->os2->size, ttf->maxp->size); ttf_save_eot(ttf, "testfont.eot"); ttf_save(ttf, "testfont.ttf");