From 114fd977a15dcc7a9b52700279576cba80e6dc09 Mon Sep 17 00:00:00 2001 From: Matthias Kramm Date: Tue, 2 Mar 2010 16:14:17 -0800 Subject: [PATCH] added eot support to ttf library --- lib/gfxfont.c | 12 +- lib/gfxfont.h | 1 + lib/ttf.c | 380 +++++++++++++++++++++++++++++++++++++++++++++++++-------- lib/ttf.h | 6 +- lib/types.h | 11 +- 5 files changed, 353 insertions(+), 57 deletions(-) diff --git a/lib/gfxfont.c b/lib/gfxfont.c index d7a8803..d206324 100644 --- a/lib/gfxfont.c +++ b/lib/gfxfont.c @@ -699,7 +699,10 @@ ttf_t* gfxfont_to_ttf(gfxfont_t*font) ttf->descent = font->descent; ttf->lineGap = font->ascent + font->descent; - ttf->name = strdup(font->id); + ttf->full_name = strdup(font->id); + ttf->family_name = strdup(font->id); + ttf->subfamily_name = strdup(font->id); + ttf->version_string = strdup("Version 1.0"); ttf_create_truetype_tables(ttf); return ttf; @@ -712,3 +715,10 @@ void gfxfont_save(gfxfont_t*font, const char*filename) ttf_destroy(ttf); } +void gfxfont_save_eot(gfxfont_t*font, const char*filename) +{ + ttf_t*ttf = gfxfont_to_ttf(font); + ttf_save_eot(ttf, filename); + ttf_destroy(ttf); +} + diff --git a/lib/gfxfont.h b/lib/gfxfont.h index f31d71f..a553ea4 100644 --- a/lib/gfxfont.h +++ b/lib/gfxfont.h @@ -34,6 +34,7 @@ extern "C" { still looks good. 1=normal, 0.5=double resolution etc. */ gfxfont_t* gfxfont_load(char*id, char*filename, unsigned int flags, double quality); void gfxfont_save(gfxfont_t*font, const char*filename); +void gfxfont_save_eot(gfxfont_t*font, const char*filename); void gfxfont_fix_unicode(gfxfont_t*font); void gfxfont_free(gfxfont_t*font); diff --git a/lib/ttf.c b/lib/ttf.c index 5aa6e10..a5bcfe4 100644 --- a/lib/ttf.c +++ b/lib/ttf.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "log.h" #include "os.h" #include "q.h" @@ -117,6 +118,10 @@ static void readBlock(memreader_t*r, void*dest, int len) r->pos += len; } } +static void reader_reset(memreader_t*r) +{ + r->pos; +} #define INIT_READ(r,data,length,pos) memreader_t r = {(data),(pos),(length)}; static void expand(ttf_table_t*w, int newsize) @@ -139,6 +144,13 @@ static inline void writeU16(ttf_table_t*w, unsigned short v) w->data[w->len++] = v>>8; w->data[w->len++] = v; } +static inline void writeU16_LE(ttf_table_t*w, unsigned short v) +{ + if(w->memsizelen+2) + expand(w, w->len+2); + w->data[w->len++] = v; + w->data[w->len++] = v>>8; +} #define writeS16 writeU16 static inline void writeU32(ttf_table_t*w, unsigned long v) { @@ -149,6 +161,15 @@ static inline void writeU32(ttf_table_t*w, unsigned long v) w->data[w->len++] = v>>8; w->data[w->len++] = v; } +static inline void writeU32_LE(ttf_table_t*w, unsigned long v) +{ + if(w->memsizelen+4) + expand(w, w->len+4); + w->data[w->len++] = v; + w->data[w->len++] = v>>8; + w->data[w->len++] = v>>16; + w->data[w->len++] = v>>24; +} static inline void writeBlock(ttf_table_t*w, void*data, int len) { if(w->memsizelen+len) @@ -1450,6 +1471,13 @@ void cmap_delete(ttf_t*ttf) } ttf->unicode_size=0; } +static char*readString(memreader_t*r, int len) +{ + char*s = malloc(len+1); + readBlock(r, s, len); + s[len] = 0; + return s; +} void name_parse(memreader_t*r, ttf_t*ttf) { U16 format = readU16(r); @@ -1464,37 +1492,90 @@ void name_parse(memreader_t*r, ttf_t*ttf) U16 name_id = readU16(r); U16 len = readU16(r); U16 offset_2 = readU16(r); + + INIT_READ(ss, r->mem, 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); + } + if(name_id==3) { + if(ttf->version_string) free(ttf->version_string); + ttf->version_string = readString(&s, len); + } if(name_id==4) { - if(ttf->name) - free(ttf->name); - ttf->name = strdup_n(&r->mem[offset+offset_2], len); + if(ttf->full_name) free(ttf->full_name); + ttf->full_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}; + writeU16(table, 0); //format - writeU16(table, 1); //count - int offset = 18; - writeU16(table, offset); //offset - - writeU16(table, 1); //platform id - writeU16(table, 0); //encoding id - writeU16(table, 0); //language - writeU16(table, 4); //4: full name - int len = strlen(ttf->name); - writeU16(table, len); - writeU16(table, table->len+2 - offset); + int count = 0; int t; - for(t=0;tname[t]); + int nr = sizeof(strings)/sizeof(strings[0]); + + for(t=0;tlen; + writeU16(table, 0); //offset (will be filled in later) + + int offset = 0; + for(t=0;tdata[offset_pos] = table->len>>8; + table->data[offset_pos+1] = table->len; + + for(t=0;tname) { - free(ttf->name); - ttf->name=0; + if(ttf->full_name) { + free(ttf->full_name); + ttf->full_name=0; + } + if(ttf->family_name) { + free(ttf->family_name); + ttf->family_name=0; + } + if(ttf->subfamily_name) { + free(ttf->subfamily_name); + ttf->subfamily_name=0; + } + if(ttf->version_string) { + free(ttf->version_string); + ttf->version_string=0; } } @@ -1642,43 +1723,58 @@ static int ttf_parse_tables(ttf_t*ttf) static void ttf_collapse_tables(ttf_t*ttf) { ttf_table_t*table; - - table = ttf_addtable(ttf, TAG_MAXP); - maxp_write(ttf, table); - maxp_delete(ttf); + + ttf_table_t*head = ttf_find_table(ttf, TAG_HEAD); + if(head) + return; //already collapsed + + if(ttf->maxp) { + table = ttf_addtable(ttf, TAG_MAXP); + maxp_write(ttf, table); + maxp_delete(ttf); + } - table = ttf_addtable(ttf, TAG_OS2); - os2_write(ttf, table); - os2_delete(ttf); + if(ttf->os2) { + table = ttf_addtable(ttf, TAG_OS2); + os2_write(ttf, table); + os2_delete(ttf); + } - if(!ttf->is_vertical) { - table = ttf_addtable(ttf, TAG_HMTX); - int num_advances = mtx_write(ttf, table); - table = ttf_addtable(ttf, TAG_HHEA); - hea_write(ttf, table, num_advances); - } else { - table = ttf_addtable(ttf, TAG_VMTX); - int num_advances = mtx_write(ttf, table); - table = ttf_addtable(ttf, TAG_VHEA); - hea_write(ttf, table, num_advances); + if(ttf->hea) { + if(!ttf->is_vertical) { + table = ttf_addtable(ttf, TAG_HMTX); + int num_advances = mtx_write(ttf, table); + table = ttf_addtable(ttf, TAG_HHEA); + hea_write(ttf, table, num_advances); + hea_delete(ttf); + } else { + table = ttf_addtable(ttf, TAG_VMTX); + int num_advances = mtx_write(ttf, table); + table = ttf_addtable(ttf, TAG_VHEA); + hea_write(ttf, table, num_advances); + hea_delete(ttf); + } } int loca_size=0; if(ttf->num_glyphs) { - table = ttf_addtable(ttf, TAG_CMAP); - cmap_write(ttf, table); - cmap_delete(ttf); + if(ttf->unicode) { + table = ttf_addtable(ttf, TAG_CMAP); + cmap_write(ttf, table); + cmap_delete(ttf); + } - table = ttf_addtable(ttf, TAG_GLYF); - U32*locations = glyf_write(ttf, table); - glyf_delete(ttf); - - table = ttf_addtable(ttf, TAG_LOCA); - loca_size = loca_write(ttf, table, locations); - free(locations); + if(ttf->glyphs) { + table = ttf_addtable(ttf, TAG_GLYF); + U32*locations = glyf_write(ttf, table); + table = ttf_addtable(ttf, TAG_LOCA); + loca_size = loca_write(ttf, table, locations); + free(locations); + glyf_delete(ttf); + } } - if(ttf->name) { + if(ttf->full_name || ttf->family_name || ttf->subfamily_name) { table = ttf_addtable(ttf, TAG_NAME); name_write(ttf, table); name_delete(ttf); @@ -1711,6 +1807,62 @@ ttf_t* ttf_load(void*data, int length) ttf_t*ttf = rfx_calloc(sizeof(ttf_t)); ttf->version = readU32(&r); + if(ttf->version == SWAP32(length)) { + U32 fontDataSize = readU32(&r); + U32 version = readU32(&r); + U32 flags = readU32(&r); + U8 panose[10]; + readBlock(&r, panose, 10); + readU8(&r); //charset + readU8(&r); //italoc + readU32(&r); //weight + readU16(&r); //fstype + U16 magic = readU16(&r); //magicNumber + /* we're being paranoid: it's entirely possible for the font + size to be exactly 0x10000. Only treat this font as eot if + it has the right magic number */ + if(magic == 0x4c50) { + readU32(&r); //unicoderange[0] + readU32(&r); //unicoderange[1] + readU32(&r); //unicoderange[2] + readU32(&r); //unicoderange[3] + readU32(&r); //codepagerange[0] + readU32(&r); //codepagerange[1] + readU32(&r); //checksumadjustment + readU32(&r); //reserved[0] + readU32(&r); //reserved[1] + readU32(&r); //reserved[2] + readU32(&r); //reserved[3] + readU16(&r); //padding + + int nr=0; + for(nr=0;nr<4;nr++) { + int t, len; + /* All of ttf is big-endian. All of ttf? No. One small eot table + of indomitable little-endian... */ + len = readU8(&r); + len |= readU8(&r)<<8; + len /= 2; + for(t=0;t>8; + } + readU16(&r); // zero terminator + } + readU16(&r); // more padding + + /* adjust the offset to the start of the actual truetype + data- the positions in the table header will be relative + to the ttf data after the header, not to the file */ + r.mem += r.pos; + r.size -= r.pos; + r.pos = 0; + ttf->version = readU32(&r); + } else { + reader_reset(&r); + ttf->version = readU32(&r); + } + } + if(ttf->version == TTCFTAG) { /* a ttc collection is a number of truetype fonts packaged together */ @@ -1736,7 +1888,7 @@ ttf_t* ttf_load(void*data, int length) readU16(&r); //range shift if(num_tables*16 > length) { - msg(" Truncated TTC file (table entries: %d)", num_tables); + msg(" Truncated TTF file (table entries: %d)", num_tables); if(ttf->version != OPENTYPE && ttf->version != TRUETYPE_MACOS && ttf->version != VERSION_1_0) { @@ -1797,7 +1949,8 @@ void ttf_create_truetype_tables(ttf_t*ttf) if(!ttf->post) ttf->post = post_new(ttf); } -ttf_table_t* ttf_write(ttf_t*ttf) + +ttf_table_t* ttf_write(ttf_t*ttf, U32*checksum_adjust) { ttf_collapse_tables(ttf); @@ -1858,6 +2011,8 @@ ttf_table_t* ttf_write(ttf_t*ttf) writeBlock(file, zero, (-t->len)&3); //pad } U32 checksum = 0xb1b0afba - ttf_table_checksum(file); + if(checksum_adjust) + *checksum_adjust = checksum; U8*checksum2 = file->data + head_pos + 8; checksum2[0] = checksum>>24; checksum2[1] = checksum>>16; @@ -1865,9 +2020,125 @@ ttf_table_t* ttf_write(ttf_t*ttf) checksum2[3] = checksum>>0; return file; } + +ttf_table_t* ttf_eot_head(ttf_t*ttf) +{ + ttf_table_t*file = ttf_table_new(0); + writeU32(file, 0); //file size (filled in later) + writeU32(file, 0); //fontdatasize (filled in later) + writeU32(file, 0x01000200); + writeU32(file, 0); //flags + writeU8(file, ttf->os2->panose_FamilyType); + writeU8(file, ttf->os2->panose_SerifStyle); + writeU8(file, ttf->os2->panose_Weight); + writeU8(file, ttf->os2->panose_Proportion); + writeU8(file, ttf->os2->panose_Contrast); + writeU8(file, ttf->os2->panose_StrokeVariation); + writeU8(file, ttf->os2->panose_ArmStyle); + writeU8(file, ttf->os2->panose_Letterform); + writeU8(file, ttf->os2->panose_Midline); + writeU8(file, ttf->os2->panose_XHeight); + writeU8(file, 1); //charset (default) + writeU8(file, ttf->os2->fsSelection&1); //italic + writeU32_LE(file, ttf->os2->usWeightClass); + writeU16(file, 0); //fstype + writeU16(file, 0x4c50); //magic + writeU32_LE(file, ttf->os2->ulCharRange[0]); + writeU32_LE(file, ttf->os2->ulCharRange[1]); + writeU32_LE(file, ttf->os2->ulCharRange[2]); + writeU32_LE(file, ttf->os2->ulCharRange[3]); + writeU32_LE(file, ttf->os2->ulCodePageRange1); + writeU32_LE(file, ttf->os2->ulCodePageRange2); + writeU32(file, 0); //checksum adjust (filled in later) + writeU32(file, 0); //reserved[0] + writeU32(file, 0); //reserved[1] + writeU32(file, 0); //reserved[2] + writeU32(file, 0); //reserved[3] + writeU16(file, 0); //padding(1) + + int 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 + + //subfamily name + len = strlen(ttf->subfamily_name); + writeU16_LE(file, len*2); + for(t=0;tsubfamily_name[t]); + } + writeU16(file, 0); //zero byte pad + + //version string + len = strlen(ttf->version_string); + writeU16_LE(file, len*2); //len + for(t=0;tversion_string[t]); + } + writeU16(file, 0); //zero byte pad + + //full name + len = strlen(ttf->full_name); + writeU16_LE(file, len*2); //len + for(t=0;tfull_name[t]); + } + writeU16(file, 0); //zero byte pad + + writeU16(file, 0); //padding(2) + return file; +} + +void ttf_save_eot(ttf_t*ttf, const char*filename) +{ + ttf_table_t* eot = ttf_eot_head(ttf); + U32 checksum_adjust = 0; + ttf_table_t* t = ttf_write(ttf, &checksum_adjust); + + U8*len_data = eot->data; + U32 full_len = eot->len + t->len; + len_data[0] = full_len>>0; + 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; + len_data2[2] = t->len>>16; + len_data2[3] = t->len>>24; + + U8*checksum_data = eot->data + 60; + checksum_data[0] = checksum_adjust>>0; + checksum_data[1] = checksum_adjust>>8; + checksum_data[2] = checksum_adjust>>16; + checksum_data[3] = checksum_adjust>>24; + + FILE*fi = fopen(filename, "wb"); + if(!fi) { + perror(filename); + return; + } + + fwrite(eot->data, eot->len, 1, fi); + fwrite(t->data, t->len, 1, fi); + fclose(fi); + ttf_table_delete(0, t); + ttf_table_delete(0, eot); +} + void ttf_save(ttf_t*ttf, const char*filename) { - ttf_table_t* t = ttf_write(ttf); + ttf_table_t* t = ttf_write(ttf, 0); FILE*fi = fopen(filename, "wb"); if(!fi) { perror(filename); @@ -1877,6 +2148,7 @@ void ttf_save(ttf_t*ttf, const char*filename) fclose(fi); ttf_table_delete(0, t); } + void ttf_dump(ttf_t*ttf) { msg(" Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":""); @@ -1939,12 +2211,18 @@ int main(int argn, const char*argv[]) return 1; } ttf_reduce(ttf); - ttf->name = strdup("testfont"); + + ttf->full_name = strdup("Test-Normal"); + ttf->family_name = strdup("Test"); + ttf->subfamily_name = strdup("Normal"); + ttf->version_string = strdup("Version 1.0"); + if(!ttf) return 1; memfile_close(m); //ttf_dump(ttf); //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"); ttf_destroy(ttf); return 0; diff --git a/lib/ttf.h b/lib/ttf.h index 21460c1..932f5e8 100644 --- a/lib/ttf.h +++ b/lib/ttf.h @@ -146,7 +146,10 @@ typedef struct _table_post { } table_post_t; typedef struct _ttf { - char*name; + char*full_name; + char*family_name; + char*subfamily_name; + char*version_string; ttf_table_t*tables; @@ -181,5 +184,6 @@ void ttf_create_truetype_tables(ttf_t*ttf); void ttf_dump(ttf_t*ttf); void ttf_destroy(ttf_t*ttf); void ttf_save(ttf_t*ttf, const char*filename); +void ttf_save_eot(ttf_t*ttf, const char*filename); #endif diff --git a/lib/types.h b/lib/types.h index 02fe287..499c840 100644 --- a/lib/types.h +++ b/lib/types.h @@ -18,16 +18,19 @@ #define GET16(ptr) (((U16)(((U8*)(ptr))[0]))+(((U16)(((U8*)(ptr))[1]))<<8)) #define GET32(ptr) (((U16)(((U8*)(ptr))[0]))+(((U16)(((U8*)(ptr))[1]))<<8)+(((U16)(((U8*)(ptr))[2]))<<16)+(((U16)(((U8*)(ptr))[3]))<<24)) +#define SWAP16(s) ((((s)>>8)&0x00ff)|(((s)<<8)&0xff00)) +#define SWAP32(s) (SWAP16(((s)>>16)&0x0000ffff)|((SWAP16(s)<<16)&0xffff0000)) + #ifdef WORDS_BIGENDIAN -#define LE_16_TO_NATIVE(s) ((((s)>>8)&0x00ff)|(((s)<<8)&0xff00)) -#define LE_32_TO_NATIVE(s) (LE_16_TO_NATIVE(((s)>>16)&0x0000ffff)|((LE_16_TO_NATIVE(s)<<16)&0xffff0000)) +#define LE_16_TO_NATIVE(s) SWAP16(s) +#define LE_32_TO_NATIVE(s) SWAP32(s) #define BE_16_TO_NATIVE(x) (x) #define BE_32_TO_NATIVE(x) (x) #else #define LE_16_TO_NATIVE(x) (x) #define LE_32_TO_NATIVE(x) (x) -#define BE_16_TO_NATIVE(s) ((((s)>>8)&0x00ff)|(((s)<<8)&0xff00)) -#define BE_32_TO_NATIVE(s) (BE_16_TO_NATIVE(((s)>>16)&0x0000ffff)|((BE_16_TO_NATIVE(s)<<16)&0xffff0000)) +#define BE_16_TO_NATIVE(s) SWAP16(s) +#define BE_32_TO_NATIVE(s) SWAP32(s) #endif // SWF Types -- 1.7.10.4