/*----------------------------------------------------------------------- ** Load a TrueType font table into memory and return a pointer to it. ** The font's "file" and "offset_table" fields must be set before this ** routine is called. ** ** This first argument is a TrueType font structure, the second ** argument is the name of the table to retrieve. A table name ** is always 4 characters, though the last characters may be ** padding spaces. -----------------------------------------------------------------------*/ BYTE *GetTable(struct TTFONT *font, const char *name) { BYTE *ptr; ULONG x; #ifdef DEBUG_TRUETYPE debug("GetTable(file,font,\"%s\")",name); #endif /* We must search the table directory. */ ptr = font->offset_table + 12; x=0; while (TRUE) { if ( strncmp((const char*)ptr,name,4) == 0 ) { ULONG offset,length; BYTE *table; offset = getULONG( ptr + 8 ); length = getULONG( ptr + 12 ); table = (BYTE*)calloc( sizeof(BYTE), length ); try { #ifdef DEBUG_TRUETYPE debug("Loading table \"%s\" from offset %d, %d bytes",name,offset,length); #endif if ( fseek( font->file, (long)offset, SEEK_SET ) ) { throw TTException("TrueType font may be corrupt (reason 3)"); } if ( fread(table,sizeof(BYTE),length,font->file) != (sizeof(BYTE) * length)) { throw TTException("TrueType font may be corrupt (reason 4)"); } } catch (TTException& ) { free(table); throw; } return table; } x++; ptr += 16; if (x == font->numTables) { throw TTException("TrueType font is missing table"); } } } /* end of GetTable() */
/* ** This is the central routine of this section. */ void ttfont_CharStrings(TTStreamWriter& stream, struct TTFONT *font, std::vector<int>& glyph_ids) { Fixed post_format; /* The 'post' table format number. */ post_format = getFixed( font->post_table ); if( post_format.whole != 2 || post_format.fraction != 0 ) throw TTException("TrueType fontdoes not have a format 2.0 'post' table"); /* Emmit the start of the PostScript code to define the dictionary. */ stream.printf("/CharStrings %d dict dup begin\n", glyph_ids.size()); /* Emmit one key-value pair for each glyph. */ for(std::vector<int>::const_iterator i = glyph_ids.begin(); i != glyph_ids.end(); ++i) { if(font->target_type == PS_TYPE_42) /* type 42 */ { stream.printf("/%s %d def\n",ttfont_CharStrings_getname(font, *i), *i); } else /* type 3 */ { stream.printf("/%s{",ttfont_CharStrings_getname(font, *i)); tt_type3_charproc(stream, font, *i); stream.putline("}_d"); /* "} bind def" */ } } stream.putline("end readonly def"); } /* end of ttfont_CharStrings() */
TTObject::TTObject(const TTSymbol aClassName) : mObjectInstance(NULL) { TTErr err = ttEnvironment->createInstance(aClassName, &mObjectInstance, TTValue()); if (err) { TTLogError("TTObject -- error %i instantiating %s\n", err, aClassName.c_str()); throw TTException("object instantiation failed"); } }
/* ** This routine is called by the one below. ** It is also called from pprdrv_tt2.c */ const char *ttfont_CharStrings_getname(struct TTFONT *font, int charindex) { int GlyphIndex; static char temp[80]; char *ptr; ULONG len; GlyphIndex = (int)getUSHORT( font->post_table + 34 + (charindex * 2) ); if ( GlyphIndex <= 257 ) /* If a standard Apple name, */ { return Apple_CharStrings[GlyphIndex]; } else /* Otherwise, use one */ { /* of the pascal strings. */ GlyphIndex -= 258; /* Set pointer to start of Pascal strings. */ ptr = (char*)(font->post_table + 34 + (font->numGlyphs * 2)); len = (ULONG)*(ptr++); /* Step thru the strings */ while (GlyphIndex--) /* until we get to the one */ { /* that we want. */ ptr += len; len = (ULONG)*(ptr++); } if ( len >= sizeof(temp) ) { throw TTException("TrueType font file contains a very long PostScript name"); } strncpy(temp,ptr,len); /* Copy the pascal string into */ temp[len]=(char)NULL; /* a buffer and make it ASCIIz. */ return temp; } } /* end of ttfont_CharStrings_getname() */
/* ** Load the simple glyph data pointed to by glyph. ** The pointer "glyph" should point 10 bytes into ** the glyph data. */ void GlyphToType3::load_char(TTFONT* font, BYTE *glyph) { int x; BYTE c, ct; /* Read the contour endpoints list. */ epts_ctr = (int *)calloc(num_ctr,sizeof(int)); for (x = 0; x < num_ctr; x++) { epts_ctr[x] = getUSHORT(glyph); glyph += 2; } /* From the endpoint of the last contour, we can */ /* determine the number of points. */ num_pts = epts_ctr[num_ctr-1]+1; #ifdef DEBUG_TRUETYPE debug("num_pts=%d",num_pts); stream.printf("%% num_pts=%d\n",num_pts); #endif /* Skip the instructions. */ x = getUSHORT(glyph); glyph += 2; glyph += x; /* Allocate space to hold the data. */ tt_flags = (BYTE *)calloc(num_pts,sizeof(BYTE)); xcoor = (FWord *)calloc(num_pts,sizeof(FWord)); ycoor = (FWord *)calloc(num_pts,sizeof(FWord)); /* Read the flags array, uncompressing it as we go. */ /* There is danger of overflow here. */ for (x = 0; x < num_pts; ) { tt_flags[x++] = c = *(glyph++); if (c&8) /* If next byte is repeat count, */ { ct = *(glyph++); if ( (x + ct) > num_pts ) { throw TTException("Error in TT flags"); } while (ct--) { tt_flags[x++] = c; } } } /* Read the x coordinates */ for (x = 0; x < num_pts; x++) { if (tt_flags[x] & 2) /* one byte value with */ { /* external sign */ c = *(glyph++); xcoor[x] = (tt_flags[x] & 0x10) ? c : (-1 * (int)c); } else if (tt_flags[x] & 0x10) /* repeat last */ { xcoor[x] = 0; } else /* two byte signed value */ { xcoor[x] = getFWord(glyph); glyph+=2; } } /* Read the y coordinates */ for (x = 0; x < num_pts; x++) { if (tt_flags[x] & 4) /* one byte value with */ { /* external sign */ c = *(glyph++); ycoor[x] = (tt_flags[x] & 0x20) ? c : (-1 * (int)c); } else if (tt_flags[x] & 0x20) /* repeat last value */ { ycoor[x] = 0; } else /* two byte signed value */ { ycoor[x] = getUSHORT(glyph); glyph+=2; } } /* Convert delta values to absolute values. */ for (x = 1; x < num_pts; x++) { xcoor[x] += xcoor[x-1]; ycoor[x] += ycoor[x-1]; } for (x=0; x < num_pts; x++) { xcoor[x] = topost(xcoor[x]); ycoor[x] = topost(ycoor[x]); } } /* end of load_char() */
/* ** Here is the routine which ties it all together. ** ** Create the array called "sfnts" which ** holds the actual TrueType data. */ void ttfont_sfnts(TTStreamWriter& stream, struct TTFONT *font) { static const char *table_names[] = /* The names of all tables */ { /* which it is worth while */ "cvt ", /* to include in a Type 42 */ "fpgm", /* PostScript font. */ "glyf", "head", "hhea", "hmtx", "loca", "maxp", "prep" } ; struct /* The location of each of */ { ULONG oldoffset; /* the above tables. */ ULONG newoffset; ULONG length; ULONG checksum; } tables[9]; BYTE *ptr; /* A pointer into the origional table directory. */ ULONG x,y; /* General use loop countes. */ int c; /* Input character. */ int diff; ULONG nextoffset; int count; /* How many `important' tables did we find? */ ptr = font->offset_table + 12; nextoffset=0; count=0; /* ** Find the tables we want and store there vital ** statistics in tables[]. */ for (x=0; x < 9; x++ ) { do { diff = strncmp( (char*)ptr, table_names[x], 4 ); if ( diff > 0 ) /* If we are past it. */ { tables[x].length = 0; diff = 0; } else if ( diff < 0 ) /* If we haven't hit it yet. */ { ptr += 16; } else if ( diff == 0 ) /* Here it is! */ { tables[x].newoffset = nextoffset; tables[x].checksum = getULONG( ptr + 4 ); tables[x].oldoffset = getULONG( ptr + 8 ); tables[x].length = getULONG( ptr + 12 ); nextoffset += ( ((tables[x].length + 3) / 4) * 4 ); count++; ptr += 16; } } while (diff != 0); } /* end of for loop which passes over the table directory */ /* Begin the sfnts array. */ sfnts_start(stream); /* Generate the offset table header */ /* Start by copying the TrueType version number. */ ptr = font->offset_table; for (x=0; x < 4; x++) { sfnts_pputBYTE( stream, *(ptr++) ); } /* Now, generate those silly numTables numbers. */ sfnts_pputUSHORT(stream, count); /* number of tables */ if ( count == 9 ) { sfnts_pputUSHORT(stream, 7); /* searchRange */ sfnts_pputUSHORT(stream, 3); /* entrySelector */ sfnts_pputUSHORT(stream, 81); /* rangeShift */ } #ifdef DEBUG_TRUETYPE else { debug("only %d tables selected",count); } #endif /* Now, emmit the table directory. */ for (x=0; x < 9; x++) { if ( tables[x].length == 0 ) /* Skip missing tables */ { continue; } /* Name */ sfnts_pputBYTE( stream, table_names[x][0] ); sfnts_pputBYTE( stream, table_names[x][1] ); sfnts_pputBYTE( stream, table_names[x][2] ); sfnts_pputBYTE( stream, table_names[x][3] ); /* Checksum */ sfnts_pputULONG( stream, tables[x].checksum ); /* Offset */ sfnts_pputULONG( stream, tables[x].newoffset + 12 + (count * 16) ); /* Length */ sfnts_pputULONG( stream, tables[x].length ); } /* Now, send the tables */ for (x=0; x < 9; x++) { if ( tables[x].length == 0 ) /* skip tables that aren't there */ { continue; } #ifdef DEBUG_TRUETYPE debug("emmiting table '%s'",table_names[x]); #endif /* 'glyf' table gets special treatment */ if ( strcmp(table_names[x],"glyf")==0 ) { sfnts_glyf_table(stream,font,tables[x].oldoffset,tables[x].length); } else /* Other tables may not exceed */ { /* 65535 bytes in length. */ if ( tables[x].length > 65535 ) { throw TTException("TrueType font has a table which is too long"); } /* Start new string if necessary. */ sfnts_new_table(stream, tables[x].length); /* Seek to proper position in the file. */ fseek( font->file, tables[x].oldoffset, SEEK_SET ); /* Copy the bytes of the table. */ for ( y=0; y < tables[x].length; y++ ) { if ( (c = fgetc(font->file)) == EOF ) { throw TTException("TrueType font may be corrupt (reason 7)"); } sfnts_pputBYTE(stream, c); } } /* Padd it out to a four byte boundary. */ y=tables[x].length; while ( (y % 4) != 0 ) { sfnts_pputBYTE(stream, 0); y++; #ifdef DEBUG_TRUETYPE_INLINE puts("\n% pad byte:\n"); #endif } } /* End of loop for all tables */ /* Close the array. */ sfnts_end_string(stream); stream.putline("]def"); } /* end of ttfont_sfnts() */
/* ** We may have to break up the 'glyf' table. That is the reason ** why we provide this special routine to copy it into the sfnts ** array. */ void sfnts_glyf_table(TTStreamWriter& stream, struct TTFONT *font, ULONG oldoffset, ULONG correct_total_length) { ULONG off; ULONG length; int c; ULONG total=0; /* running total of bytes written to table */ int x; bool loca_is_local=false; #ifdef DEBUG_TRUETYPE debug("sfnts_glyf_table(font,%d)", (int)correct_total_length); #endif if (font->loca_table == NULL) { font->loca_table = GetTable(font,"loca"); loca_is_local = true; } /* Seek to proper position in the file. */ fseek( font->file, oldoffset, SEEK_SET ); /* Copy the glyphs one by one */ for (x=0; x < font->numGlyphs; x++) { /* Read the glyph offset from the index-to-location table. */ if (font->indexToLocFormat == 0) { off = getUSHORT( font->loca_table + (x * 2) ); off *= 2; length = getUSHORT( font->loca_table + ((x+1) * 2) ); length *= 2; length -= off; } else { off = getULONG( font->loca_table + (x * 4) ); length = getULONG( font->loca_table + ((x+1) * 4) ); length -= off; } #ifdef DEBUG_TRUETYPE debug("glyph length=%d",(int)length); #endif /* Start new string if necessary. */ sfnts_new_table( stream, (int)length ); /* ** Make sure the glyph is padded out to a ** two byte boundary. */ if ( length % 2 ) { throw TTException("TrueType font contains a 'glyf' table without 2 byte padding"); } /* Copy the bytes of the glyph. */ while ( length-- ) { if ( (c = fgetc(font->file)) == EOF ) { throw TTException("TrueType font may be corrupt (reason 6)"); } sfnts_pputBYTE(stream, c); total++; /* add to running total */ } } if (loca_is_local) { free(font->loca_table); font->loca_table = NULL; } /* Pad out to full length from table directory */ while ( total < correct_total_length ) { sfnts_pputBYTE(stream, 0); total++; } } /* end of sfnts_glyf_table() */
void read_font(const char *filename, font_type_enum target_type, std::vector<int>& glyph_ids, TTFONT& font) { BYTE *ptr; /* Decide what type of PostScript font we will be generating. */ font.target_type = target_type; if (font.target_type == PS_TYPE_42) { bool has_low = false; bool has_high = false; for (std::vector<int>::const_iterator i = glyph_ids.begin(); i != glyph_ids.end(); ++i) { if (*i > 255) { has_high = true; if (has_low) break; } else { has_low = true; if (has_high) break; } } if (has_high && has_low) { font.target_type = PS_TYPE_42_3_HYBRID; } else if (has_high && !has_low) { font.target_type = PS_TYPE_3; } } /* Save the file name for error messages. */ font.filename=filename; /* Open the font file */ if ( (font.file = fopen(filename,"rb")) == (FILE*)NULL ) { throw TTException("Failed to open TrueType font"); } /* Allocate space for the unvarying part of the offset table. */ assert(font.offset_table == NULL); font.offset_table = (BYTE*)calloc( 12, sizeof(BYTE) ); /* Read the first part of the offset table. */ if ( fread( font.offset_table, sizeof(BYTE), 12, font.file ) != 12 ) { throw TTException("TrueType font may be corrupt (reason 1)"); } /* Determine how many directory entries there are. */ font.numTables = getUSHORT( font.offset_table + 4 ); #ifdef DEBUG_TRUETYPE debug("numTables=%d",(int)font.numTables); #endif /* Expand the memory block to hold the whole thing. */ font.offset_table = (BYTE*)realloc( font.offset_table, sizeof(BYTE) * (12 + font.numTables * 16) ); /* Read the rest of the table directory. */ if ( fread( font.offset_table + 12, sizeof(BYTE), (font.numTables*16), font.file ) != (font.numTables*16) ) { throw TTException("TrueType font may be corrupt (reason 2)"); } /* Extract information from the "Offset" table. */ font.TTVersion = getFixed( font.offset_table ); /* Load the "head" table and extract information from it. */ ptr = GetTable(&font, "head"); try { font.MfrRevision = getFixed( ptr + 4 ); /* font revision number */ font.unitsPerEm = getUSHORT( ptr + 18 ); font.HUPM = font.unitsPerEm / 2; #ifdef DEBUG_TRUETYPE debug("unitsPerEm=%d",(int)font.unitsPerEm); #endif font.llx = topost2( getFWord( ptr + 36 ) ); /* bounding box info */ font.lly = topost2( getFWord( ptr + 38 ) ); font.urx = topost2( getFWord( ptr + 40 ) ); font.ury = topost2( getFWord( ptr + 42 ) ); font.indexToLocFormat = getSHORT( ptr + 50 ); /* size of 'loca' data */ if (font.indexToLocFormat != 0 && font.indexToLocFormat != 1) { throw TTException("TrueType font is unusable because indexToLocFormat != 0"); } if ( getSHORT(ptr+52) != 0 ) { throw TTException("TrueType font is unusable because glyphDataFormat != 0"); } } catch (TTException& ) { free(ptr); throw; } free(ptr); /* Load information from the "name" table. */ Read_name(&font); /* We need to have the PostScript table around. */ assert(font.post_table == NULL); font.post_table = GetTable(&font, "post"); font.numGlyphs = getUSHORT( font.post_table + 32 ); /* If we are generating a Type 3 font, we will need to */ /* have the 'loca' and 'glyf' tables arround while */ /* we are generating the CharStrings. */ if (font.target_type == PS_TYPE_3 || font.target_type == PDF_TYPE_3 || font.target_type == PS_TYPE_42_3_HYBRID) { BYTE *ptr; /* We need only one value */ ptr = GetTable(&font, "hhea"); font.numberOfHMetrics = getUSHORT(ptr + 34); free(ptr); assert(font.loca_table == NULL); font.loca_table = GetTable(&font,"loca"); assert(font.glyf_table == NULL); font.glyf_table = GetTable(&font,"glyf"); assert(font.hmtx_table == NULL); font.hmtx_table = GetTable(&font,"hmtx"); } if (glyph_ids.size() == 0) { glyph_ids.clear(); glyph_ids.reserve(font.numGlyphs); for (int x = 0; x < font.numGlyphs; ++x) { glyph_ids.push_back(x); } } else if (font.target_type == PS_TYPE_3 || font.target_type == PS_TYPE_42_3_HYBRID) { ttfont_add_glyph_dependencies(&font, glyph_ids); } } /* end of insert_ttfont() */