#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)
{
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;
}
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)
for(t=0;t<ttf->num_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;
}
int t;
for(t=0;t<num_advances;t++) {
writeU16(w, ttf->glyphs[t].advance);
- writeU16(w, ttf->glyphs[t].bearing);
+ writeS16(w, ttf->glyphs[t].bearing);
}
for(;t<ttf->num_glyphs;t++) {
- writeU16(w, ttf->glyphs[t].bearing);
+ writeS16(w, ttf->glyphs[t].bearing);
}
return num_advances;
}
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;
+ int range_shift = num_segments*2 - search_range*2;
w->data[num_segments_pos++]=range_shift>>8;
w->data[num_segments_pos++]=range_shift;
U16 len = readU16(r);
U16 offset_2 = readU16(r);
+ char ** read_name = 0;
+
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);
+ 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->family_name, ttf->subfamily_name, ttf->version_string, ttf->full_name};
- int codes[4] = {1,2,3,4};
+ 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;
free(ttf->version_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)
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)
{
}
}
+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;t<cvt->num;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;t<cvt->num;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;t<num;t++) {
+ gasp->records[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;t<gasp->num;t++) {
+ if(gasp->records[t].behaviour & ~(GASP_GRIDFIT | GASP_DOGRAY)) {
+ version = 1;
+ }
+ }
+ writeU16(table, version);
+ writeU16(table, gasp->num);
+ for(t=0;t<gasp->num;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;
ttf_table_delete(ttf, table);
}
+ table = ttf_find_table(ttf, TAG_CVT);
+ if(table) {
+ INIT_READ(m, table->data, table->len, 0);
+ 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);
+ }
+
return 1;
}
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);
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);
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("<error> TTF Table %02x%02x%02x%02x outside of stream (pos %d)", (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, pos);
} else {
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)
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;t<len;t++) {
- writeU8(file, 0);
- writeU8(file, ttf->family_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;t<len;t++) {
- writeU8(file, 0);
- writeU8(file, ttf->subfamily_name[t]);
- }
- writeU16(file, 0); //zero byte pad
+ for(i=0;i<nr;i++) {
+ char *string = strings[i];
- //version string
- len = strlen(ttf->version_string);
- writeU16_LE(file, len*2); //len
- for(t=0;t<len;t++) {
- writeU8(file, 0);
- writeU8(file, ttf->version_string[t]);
+ //family name
+ len = strlen(string);
+ writeU16_LE(file, len*2);
+ for(t=0;t<len;t++) {
+ writeU8(file, 0);
+ writeU8(file, string[t]);
+ }
+ writeU16(file, 0); //zero byte pad
}
- writeU16(file, 0); //zero byte pad
- //full name
- len = strlen(ttf->full_name);
- writeU16_LE(file, len*2); //len
- for(t=0;t<len;t++) {
- writeU8(file, 0);
- writeU8(file, ttf->full_name[t]);
- }
writeU16(file, 0); //zero byte pad
writeU16(file, 0); //padding(2)
hea_delete(ttf);
glyf_delete(ttf);
post_delete(ttf);
+ cvt_delete(ttf);
name_delete(ttf);
free(ttf);
}
}
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);