| | |
The TrueType Font (TTF) format is a widely used font file format in digital typography, designed by Apple and Microsoft.
It utilizes quadratic Bézier curves to define glyph shapes, allowing for smooth rendering at various sizes.
TTF files contain data such as glyph outlines, metrics, and hinting instructions, ensuring consistent appearance across different devices and resolutions. Additionally, TrueType fonts support advanced typographic features like ligatures, kerning pairs, and stylistic alternates, making them versatile for various design needs.
TTF files are commonly used on both Windows and macOS platforms, as well as in web typography due to their widespread compatibility and compact file size.
/******************************************************************************/ /* */ /* File: ttf.h */ /* Author: bkenwright@xbdev.net */ /* URL: www.xbdev.net */ /* */ /******************************************************************************/ /* ttf font file format reader
Desc? Well this whole file reads the ttf font file in, parses it and stores it in various structures.
You pass it a stTTF structure, and it fills it in with all the information, such as supported characters, glyfs, etc
File to use:
void ReadTTF(const char* szFileName, stTTF* ttf)
*/ /******************************************************************************/
#pragma once
#include "dxdebug.h"
const int MAXFLAGS = 1500;
typedef short int int16; typedef int int32; typedef unsigned int uint32; typedef unsigned short uint16; typedef unsigned char uchar8; typedef unsigned char uint8; typedef short FWord; // - 16-bit signed integer that describes a quantity in FUnits, // the smallest measurable distance in em space. typedef unsigned int Fixed; typedef double longDateTime;
#pragma pack(1) struct stOffsetSubTable { uint32 scaler; // type A tag to indicate the OFA scaler to be used to // rasterize this font; see the note on the scaler type below for more information. uint16 numTables; // number of tables uint16 searchRange; // (maximum power of 2 <= numTables)*16 uint16 entrySelector; // log2(maximum power of 2 <= numTables) uint16 rangeShift; // numTables*16-searchRange }; #pragma pack()
struct stTableDirectory { uint32 tag; // 4-byte identifier uint32 checkSum; // checksum for this table uint32 offset; // offset from beginning of sfnt uint32 length; // length of this table in byte (actual length not padded length) };
struct stFontDirectory { stFontDirectory() { m_tableDirectory=NULL; } ~stFontDirectory() { delete[] m_tableDirectory; }
stOffsetSubTable m_offsetSubTable; stTableDirectory* m_tableDirectory; };
struct stCMAPTable { uint16 format; // hopefully 0 for easy fonts uint16 length; // 262 for format 0 uint16 language; // language-independent };
struct stCMAPSubTable { uint16 platformID; // Platform identifier uint16 platformSpecificID; // Platform-specific encoding identifier uint32 offset; // Offset of the mapping table
stCMAPTable table; // Offset points to this };
struct stCMAP { stCMAP() { subTables=NULL;
numGlyphIndexArray=0; glyphIndexArray=NULL; } ~stCMAP() { if (subTables) delete[] subTables; subTables=NULL;
if (glyphIndexArray) delete[] glyphIndexArray; glyphIndexArray=NULL; }
uint16 version; // Version number (Set to zero) uint16 numberSubtables; // Number of encoding subtables
stCMAPSubTable* subTables;
int numGlyphIndexArray; uint8* glyphIndexArray; };
struct stGlyfDescription { int16 numberOfContours; // If the number of contours is positive or zero, it is a single glyph; // If the number of contours is -1, the glyph is compound FWord xMin; // Minimum x for coordinate data FWord yMin; // Minimum y for coordinate data FWord xMax; // Maximum x for coordinate data FWord yMax; // Maximum y for coordinate data
// Zero or positive number of contours signals a simple glyph. // -1, the glyph is made up of components. };
struct stGLYFSimple { stGLYFSimple() { instructions = NULL; endPtsOfContours = NULL; flags = NULL; xCoordinates = NULL; yCoordinates = NULL; } ~stGLYFSimple() { delete[] instructions; instructions=NULL; delete[] endPtsOfContours; endPtsOfContours=NULL; delete[] flags; flags=NULL; delete[] xCoordinates; xCoordinates=NULL; delete[] yCoordinates; yCoordinates=NULL; }
uint16* endPtsOfContours; // [n] Array of last points of each contour; n is the number of contours; array entries are point indices uint16 instructionLength; // Total number of bytes needed for instructions uint8* instructions; // [instructionLength] Array of instructions for this glyph int numFlags; uint8* flags; // [variable] Array of flags int16* xCoordinates; // uint8 or int16 - Array of x-coordinates; the first is relative to (0,0), others are relative to previous point int16* yCoordinates; // uint8 or int16 - Array of y-coordinates; the first is relative to (0,0), others are relative to previous point };
struct stGLYFCompound { union { uint16 flags; // Component flag struct { uint16 ARG_1_AND_2_ARE_WORDS : 1; // 0 If set, the arguments are words; // If not set, they are bytes. uint16 ARGS_ARE_XY_VALUES : 1; // 1 If set, the arguments are xy values; // If not set, they are points. uint16 ROUND_XY_TO_GRID : 1; // 2 If set, round the xy values to grid; // if not set do not round xy values to grid (relevant only to bit 1 is set) uint16 WE_HAVE_A_SCALE : 1; // 3 If set, there is a simple scale for the component. // If not set, scale is 1.0. // (this bit is obsolete) 4 (obsolete; set to zero) uint16 MORE_COMPONENTS : 1; // 5 If set, at least one additional glyph follows this one. uint16 WE_HAVE_AN_X_AND_Y_SCALE : 1; // 6 If set the x direction will use a different scale than the y direction. uint16 WE_HAVE_A_TWO_BY_TWO : 1; // 7 If set there is a 2-by-2 transformation that will be used to scale the component. uint16 WE_HAVE_INSTRUCTIONS : 1; // 8 If set, instructions for the component character follow the last component. uint16 USE_MY_METRICS : 1; // 9 Use metrics from this component for the compound glyph. uint16 OVERLAP_COMPOUND : 1; // 10 If set, the components of this compound glyph overlap. }flagBits; };
uint16 glyphIndex; // Glyph index of component int32 offset0; int32 offset1; // int16, uint16, int8 or uint8 argument1 X-offset for component or point number; type depends on bits 0 and 1 in component flags // int16, uint16, int8 or uint8 argument2 Y-offset for component or point number type depends on bits 0 and 1 in component flags // transformation option One of the transformation options from Table 19 };
struct stGLYFItem { stGLYFItem() { m_glyfSimple=NULL; m_glyfCompound=NULL; } ~stGLYFItem() { delete m_glyfSimple; m_glyfSimple=NULL; delete m_glyfCompound; m_glyfCompound=NULL; }
stGlyfDescription m_glyfDescription; // (here follow the data for the simple or compound glyph) stGLYFSimple* m_glyfSimple; stGLYFCompound* m_glyfCompound; };
struct stGLYF { stGLYF() { glyfItem=NULL; numGlyphs=0; } ~stGLYF() { if (glyfItem) { delete[] glyfItem; glyfItem=NULL; }; };
int numGlyphs; // Set from 'maxp' table stGLYFItem* glyfItem; // Array };
struct stHEAD { Fixed version; // 0x00010000 if (version 1.0) Fixed fontRevision; // set by font manufacturer uint32 checkSumAdjustment; // To compute: set it to 0, calculate the checksum for the 'head' table and put it in the table directory, sum the entire font as uint32, then store B1B0AFBA - sum. The checksum for the 'head' table will not be wrong. That is OK. uint32 magicNumber; // set to 0x5F0F3CF5 uint16 flags; // bit 0 - y value of 0 specifies baseline // bit 1 - x position of left most black bit is LSB // bit 2 - scaled point size and actual point size will differ (i.e. 24 point glyph differs from 12 point glyph scaled by factor of 2) // bit 3 - use integer scaling instead of fractional // bit 4 - (used by the Microsoft implementation of the TrueType scaler) // bit 5 - This bit should be set in fonts that are intended to e laid out vertically, and in which the glyphs have been drawn such that an x-coordinate of 0 corresponds to the desired vertical baseline. // bit 6 - This bit must be set to zero. // bit 7 - This bit should be set if the font requires layout for correct linguistic rendering (e.g. Arabic fonts). // bit 8 - This bit should be set for a GX font which has one or more metamorphosis effects designated as happening by default. // bit 9 - This bit should be set if the font contains any strong right-to-left glyphs. // bit 10 - This bit should be set if the font contains Indic-style rearrangement effects. // bits 11-12 - Defined by Adobe. uint16 unitsPerEm; // range from 64 to 16384 longDateTime created; // international date longDateTime modified; // international date FWord xMin; // for all glyph bounding boxes FWord yMin; // for all glyph bounding boxes FWord xMax; // for all glyph bounding boxes FWord yMax; // for all glyph bounding boxes uint16 macStyle; // bit 0 bold // bit 1 italic // bit 2 underline // bit 3 outline // bit 4 shadow // bit 5 condensed (narrow) // bit 6 extended uint16 lowestRecPPEM; // smallest readable size in pixels int16 fontDirectionHint; // 0 Mixed directional glyphs // 1 Only strongly left to right glyphs // 2 Like 1 but also contains neutrals // -1 Only strongly right to left glyphs // -2 Like -1 but also contains neutrals int16 indexToLocFormat; // 0 for short offsets, 1 for long int16 glyphDataFormat; // 0 for current format };
struct stLOCA { stLOCA() { glyphOffsets=NULL; } ~stLOCA() { delete[] glyphOffsets; glyphOffsets=NULL; }
int* glyphOffsets; };
struct stMAXP { Fixed version; // 0x00010000 (1.0) uint16 numGlyphs; // the number of glyphs in the font uint16 maxPoints; // points in non-compound glyph uint16 maxContours; // contours in non-compound glyph uint16 maxComponentPoints; // points in compound glyph uint16 maxComponentContours; // contours in compound glyph uint16 maxZones; // set to 2 uint16 maxTwilightPoints; // points used in Twilight Zone (Z0) uint16 maxStorage; // number of Storage Area locations uint16 maxFunctionDefs; // number of FDEFs uint16 maxInstructionDefs; // number of IDEFs uint16 maxStackElements; // maximum stack depth uint16 maxSizeOfInstructions; // byte count for glyph instructions uint16 maxComponentElements; // number of glyphs referenced at top level uint16 maxComponentDepth; // levels of recursion, set to 0 if font has only simple glyphs };
struct stTTF { stFontDirectory m_fontDirectory; stCMAP m_cmap; stHEAD m_head; stGLYF m_glyf; stLOCA m_loca; stMAXP m_maxp; };
inline void SwapEndian(unsigned char *data) { //do nothing, just needed for completeness }
inline void SwapEndian(char *data) { //do nothing, just needed for completeness }
inline void SwapEndian(unsigned short *data) { *data=((*data&0x00ff)<<8) |((*data&0xff00)>>8); }
inline void SwapEndian(short *data) { *data=((*data&0x00ff)<<8) |((*data&0xff00)>>8); }
inline void SwapEndian(unsigned int *data) { *data=((*data&0x000000ff)<<24) |((*data&0x0000ff00)<< 8) |((*data&0x00ff0000)>> 8) |((*data&0xff000000)>>24); }
inline void SwapEndian(int *data) { *data=((*data&0x000000ff)<<24) |((*data&0x0000ff00)<< 8) |((*data&0x00ff0000)>> 8) |((*data&0xff000000)>>24); }
/******************************************************************************/
inline int FileSize(FILE *fp) { long pos; fseek(fp, 0, SEEK_END); pos = ftell(fp); fseek(fp, 0, SEEK_SET); return pos; }
/******************************************************************************/
void ReadTableDirectory(FILE* fp, stTableDirectory* td) { fread(&td->tag, sizeof(td->tag), 1, fp); fread(&td->checkSum, sizeof(td->checkSum), 1, fp); fread(&td->offset, sizeof(td->offset), 1, fp); fread(&td->length, sizeof(td->length), 1, fp); //SwapEndian(&td->tag); // Don't need to flip 4 seperate bytes SwapEndian(&td->checkSum); SwapEndian(&td->offset); SwapEndian(&td->length);
char* t = (char*)&td->tag; dprintf("\t [Tag: %c%c%c%c],", t[0], t[1], t[2], t[3] ); dprintf(" CheckSum 0x%08X,", td->checkSum); dprintf(" Offset % 8d,", td->offset); dprintf(" Length: % 6d\n", td->length); }
void ReadFontDirectory(FILE* fp, stFontDirectory* fd) { dprintf("FontDirectory:\n"); stOffsetSubTable* ot = &fd->m_offsetSubTable;
fread(&ot->scaler, sizeof(ot->scaler), 1, fp); SwapEndian(&ot->scaler); DBG_ASSERT(ot->scaler==0x00010000);
fread(&ot->numTables, sizeof(ot->numTables), 1, fp); fread(&ot->searchRange, sizeof(ot->searchRange), 1, fp); fread(&ot->entrySelector, sizeof(ot->entrySelector), 1, fp); fread(&ot->rangeShift, sizeof(ot->rangeShift), 1, fp); SwapEndian(&ot->numTables); SwapEndian(&ot->searchRange); SwapEndian(&ot->entrySelector); SwapEndian(&ot->rangeShift);
dprintf("\tOffsetSubTable\n"); dprintf("\t Scalar: 0x%08X\n", ot->scaler); dprintf("\t NumTables: %d\n", ot->numTables); dprintf("\t SearchRange: %d\n", ot->searchRange); dprintf("\t EntrySelector: %d\n", ot->entrySelector); dprintf("\t RangeShift: %d\n", ot->rangeShift);
DBG_ASSERT(ot->numTables<MAXFLAGS); // Sanity check
fd->m_tableDirectory = new stTableDirectory[ot->numTables];
dprintf("\n\tTableDirectory\n"); for (int i=0; i<ot->numTables; i++) { ReadTableDirectory(fp, &fd->m_tableDirectory[i]); } }
/******************************************************************************/
uchar8* GetTableData(uchar8* data, stTTF* ttf, char* name) { stFontDirectory* fd = &ttf->m_fontDirectory; stOffsetSubTable* subTable = &fd->m_offsetSubTable;
stTableDirectory* tableDirectory = NULL; for (int i=0; i<subTable->numTables; i++) { stTableDirectory* table = &fd->m_tableDirectory[i]; char* c = (char*)&table->tag;
char tname[32] = {0}; strncpy(tname, c, 4);
if (strcmp(tname, name)==0) { tableDirectory = table; break; }
} DBG_ASSERT(tableDirectory);
uchar8* tableData = &data[tableDirectory->offset];
return tableData; }
/******************************************************************************/
void ReadCMAP(uchar8* data, stTTF* ttf, stCMAP* cmap) { uchar8* cmapData = GetTableData(data, ttf, "cmap"); DBG_ASSERT(cmapData); uchar8* startCMAPData = cmapData;
cmap->version = *((uint16*)cmapData); cmapData+=2; SwapEndian(&cmap->version); cmap->numberSubtables = *((uint16*)cmapData); cmapData+=2; SwapEndian(&cmap->numberSubtables);
int numSubTables = cmap->numberSubtables; DBG_ASSERT(numSubTables>0 && numSubTables<1000); // Sanity check cmap->subTables = new stCMAPSubTable[numSubTables]; DBG_ASSERT(cmap->subTables);
for (int i=0; i<numSubTables; i++) { stCMAPSubTable* subTable = &cmap->subTables[i];
subTable->platformID = *((uint16*)cmapData); cmapData+=2; SwapEndian(&subTable->platformID); subTable->platformSpecificID = *((uint16*)cmapData); cmapData+=2; SwapEndian(&subTable->platformSpecificID); subTable->offset = *((uint32*)cmapData); cmapData+=4; SwapEndian(&subTable->offset);
stCMAPTable* table = &subTable->table; uchar8* tableOffset = startCMAPData + subTable->offset;
table->format = *((uint16*)tableOffset); tableOffset+=2; SwapEndian(&table->format); table->length = *((uint16*)tableOffset); tableOffset+=2; SwapEndian(&table->length); table->language = *((uint16*)tableOffset); tableOffset+=2; SwapEndian(&table->language);
switch (table->format) { case 0: // Table follows as 256 glyph indices { // Character codes and glyph indices that are restricted to a single byte DBG_ASSERT(table->length == 262);
DBG_ASSERT(cmap->glyphIndexArray==NULL); if (cmap->glyphIndexArray==NULL) { cmap->glyphIndexArray = new uint8[256]; cmap->numGlyphIndexArray = 256; uint8* glyphIndexArray = cmap->glyphIndexArray;
for (int k=0; k<256; k++) { glyphIndexArray[k] = *((uint8*)tableOffset); tableOffset+=1; } } } break;
default: { //DBG_HALT; } } } }
/******************************************************************************/
int ReadCoords(uint8* data, int numFlags, uint8* flags, int16* coords, bool isX) { uint8* startAddr = data;
int point = 0; const int MAXPOINTS = MAXFLAGS; int points[MAXPOINTS]; int numPoints = 0; for (int i=0; i<numFlags; i++) { DBG_ASSERT(numPoints<MAXPOINTS); uint8 flag = flags[i];
bool isByte = false; bool isSame = false; if (isX) { isByte = (flag&2) > 0 ? true : false; isSame = (flag&16) > 0 ? true : false; } else { isByte = (flag&4) > 0 ? true : false; isSame = (flag&32) > 0 ? true : false; }
if (isByte) { uint8 coord = *((uint8*)data); data+=1; SwapEndian(&coord); int16 scoord = coord; if (!isSame) scoord = -scoord; point += scoord; } else { if (isSame) { // same as last point } else { int16 coord = *((int16*)data); data+=2; SwapEndian(&coord); point += coord; } } points[numPoints++] = point; }
DBG_ASSERT(numPoints == numFlags); for (int i=0; i<numPoints; i++) { coords[i] = points[i]; }
int bytesRead = (int)(data - startAddr); return bytesRead; }
/******************************************************************************/
void ReadGLYFSimple(uchar8* data, stGLYFItem* glyfItem, int indx) { //int numPoints = indx; // index refers to last point.
int numPoints = -1;
glyfItem->m_glyfSimple = new stGLYFSimple; stGLYFSimple* glyfSimple = glyfItem->m_glyfSimple;
int numberOfContours = glyfItem->m_glyfDescription.numberOfContours; DBG_ASSERT(numberOfContours>0 && numberOfContours<10000);
glyfSimple->endPtsOfContours = new uint16[numberOfContours]; for (int i=0; i<numberOfContours; i++) { glyfSimple->endPtsOfContours[i] = *((uint16*)data); data+=2; SwapEndian(&glyfSimple->endPtsOfContours[i]);
if (glyfSimple->endPtsOfContours[i] > numPoints) { numPoints = glyfSimple->endPtsOfContours[i]; } }
DBG_ASSERT(numPoints>=0); DBG_ASSERT(numPoints<2000);
glyfSimple->instructionLength = *((uint16*)data); data+=2; SwapEndian(&glyfSimple->instructionLength); /// DBG_ASSERT(glyfSimple->instructionLength>0 && glyfSimple->instructionLength<10000);
glyfSimple->instructions = new uint8[ glyfSimple->instructionLength ];
for (int i=0; i<glyfSimple->instructionLength; i++) { glyfSimple->instructions[i] = *((uint8*)data); data+=1; SwapEndian(&glyfSimple->instructions[i]); }
uint8 flags[MAXFLAGS];
numPoints++; int numFlags = 0; while (numFlags < numPoints) { DBG_ASSERT(numFlags < MAXFLAGS);
uint8 flag = *((uint8*)data); data+=1; SwapEndian(&flag); flags[numFlags] = flag; numFlags++;
uint8 repeat = (flag & 0x8); // Get Repeat Flag
if (repeat) { ///????ERROR???...should repeat and call itself? uint8 numRepeats = *((uint8*)data); data+=1; SwapEndian(&numRepeats); for (int i=0; i<numRepeats; i++) { flags[numFlags] = flag; numFlags++; } } }
if (indx==68) { int check = 0; }
glyfItem->m_glyfSimple->numFlags = numFlags; glyfItem->m_glyfSimple->flags = new uint8[numFlags]; for (int i=0; i<numFlags; i++) { glyfItem->m_glyfSimple->flags[i] = flags[i]; }
glyfItem->m_glyfSimple->xCoordinates = new int16[numFlags]; glyfItem->m_glyfSimple->yCoordinates = new int16[numFlags];
data += ReadCoords(data, numFlags, flags, glyfItem->m_glyfSimple->xCoordinates, true); // x coords
if (indx==68) { int check = 0; }
data += ReadCoords(data, numFlags, flags, glyfItem->m_glyfSimple->yCoordinates, false); // y coords
}
/******************************************************************************/
void ReadGLYFCompound(uchar8* data, stGLYFItem* glyfItem, int indx) {
const int ARG_1_AND_2_ARE_WORDS = 1<<0; // If set, the arguments are words; // If not set, they are bytes. const int ARGS_ARE_XY_VALUES = 1<<1; // If set, the arguments are xy values; // If not set, they are points. const int ROUND_XY_TO_GRID = 1<<2; // If set, round the xy values to grid; // if not set do not round xy values to grid (relevant only to bit 1 is set) const int WE_HAVE_A_SCALE = 1<<3; // If set, there is a simple scale for the component. // If not set, scale is 1.0. // (this bit is obsolete) 4 (obsolete; set to zero) const int MORE_COMPONENTS = 1<<5; // If set, at least one additional glyph follows this one. const int WE_HAVE_AN_X_AND_Y_SCALE = 1<<6; // If set the x direction will use a different scale than the y direction. const int WE_HAVE_A_TWO_BY_TWO = 1<<7; // If set there is a 2-by-2 transformation that will be used to scale the component. const int WE_HAVE_INSTRUCTIONS = 1<<8; // If set, instructions for the component character follow the last component. const int USE_MY_METRICS = 1<<9; // Use metrics from this component for the compound glyph. const int OVERLAP_COMPOUND = 1<<10; // If set, the components of this compound glyph overlap.
glyfItem->m_glyfCompound = new stGLYFCompound; stGLYFCompound* glyfCompound = glyfItem->m_glyfCompound;
uint16 flagbyte = 0; uint16 glyphIndex = 0; do { flagbyte = *((uint16*)data); data+=2; SwapEndian(&flagbyte); glyphIndex = *((uint16*)data); data+=2; SwapEndian(&glyphIndex);
if ( (flagbyte & ARGS_ARE_XY_VALUES) == 0 ) { DBG_HALT; // index } else { if ( flagbyte & ARG_1_AND_2_ARE_WORDS ) { uint16 arg0 = *((uint16*)data); data+=2; SwapEndian(&arg0); uint16 arg1 = *((uint16*)data); data+=2; SwapEndian(&arg1); } else { uint8 arg0 = *((uint8*)data); data+=1; SwapEndian(&arg0); uint8 arg1 = *((uint8*)data); data+=1; SwapEndian(&arg1); } }
if (flagbyte & WE_HAVE_A_TWO_BY_TWO) { uint16 a = *((uint16*)data); data+=2; SwapEndian(&a); uint16 b = *((uint16*)data); data+=2; SwapEndian(&b); uint16 c = *((uint16*)data); data+=2; SwapEndian(&c); uint16 d = *((uint16*)data); data+=2; SwapEndian(&d); } else if (flagbyte & WE_HAVE_AN_X_AND_Y_SCALE) { uint16 a = *((uint16*)data); data+=2; SwapEndian(&a); 0; 0; uint16 d = *((uint16*)data); data+=2; SwapEndian(&d); } else if ( flagbyte & WE_HAVE_A_SCALE ) { uint16 s = *((uint16*)data); data+=2; SwapEndian(&s); s; 0; 0; s; } else { 1; 0; 0; 1; }
} while (flagbyte & MORE_COMPONENTS);
}
/******************************************************************************/
void ReadGLYF(uchar8* data, stTTF* ttf, stGLYF* glyf) { uchar8* glyfData = GetTableData(data, ttf, "glyf"); DBG_ASSERT(glyfData);
int numGlyphs = ttf->m_maxp.numGlyphs; DBG_ASSERT(numGlyphs>0 && numGlyphs<10000); // Sanity check
stLOCA* loca = &ttf->m_loca; int* glyphOffsets = loca->glyphOffsets; DBG_ASSERT(glyphOffsets);
glyf->numGlyphs = numGlyphs; glyf->glyfItem = new stGLYFItem[numGlyphs];
for (int i=0; i<numGlyphs; i++) { stGLYFItem* glyfItem = &glyf->glyfItem[i]; int glyfOffset = glyphOffsets[i]; uchar8* itemData = &glyfData[ glyfOffset ];
stGlyfDescription* glyfDesc = &glyfItem->m_glyfDescription; glyfDesc->numberOfContours = *((int16*)itemData); itemData+=2; SwapEndian(&glyfDesc->numberOfContours); glyfDesc->xMin = *((FWord*)itemData); itemData+=2; SwapEndian(&glyfDesc->xMin); glyfDesc->yMin = *((FWord*)itemData); itemData+=2; SwapEndian(&glyfDesc->yMin); glyfDesc->xMax = *((FWord*)itemData); itemData+=2; SwapEndian(&glyfDesc->xMax); glyfDesc->yMax = *((FWord*)itemData); itemData+=2; SwapEndian(&glyfDesc->yMax);
// Only Simple Glyphs at the moment DBG_ASSERT(glyfDesc->numberOfContours!=0);
if (glyfDesc->numberOfContours>0) { ReadGLYFSimple(itemData, glyfItem, i); } if (glyfDesc->numberOfContours<0) { DBG_ASSERT(glyfDesc->numberOfContours==-1); ReadGLYFCompound(itemData, glyfItem, i); } }
int done = 0;
}
/******************************************************************************/
void ReadLOCA(uchar8* data, stTTF* ttf, stLOCA* loca) { uchar8* locaData = GetTableData(data, ttf, "loca"); DBG_ASSERT(locaData);
int numGlyphs = ttf->m_maxp.numGlyphs;
DBG_ASSERT(numGlyphs>0 && numGlyphs<5000); // Sanity Check loca->glyphOffsets = new int[numGlyphs];
DBG_ASSERT(ttf->m_head.indexToLocFormat==0 || ttf->m_head.indexToLocFormat==1); bool shortOffsets = ttf->m_head.indexToLocFormat==0 ? true : false;
for (int i=0; i<numGlyphs; i++) { if (shortOffsets) { uint16 offset = *((uint16*)locaData); locaData+=2; SwapEndian(&offset); loca->glyphOffsets[i] = offset; } else { uint32 offset = *((uint32*)locaData); locaData+=4; SwapEndian(&offset); loca->glyphOffsets[i] = offset; } }
}
/******************************************************************************/
void ReadMAXP(uchar8* data, stTTF* ttf, stMAXP* maxp) { uchar8* maxpData = GetTableData(data, ttf, "maxp"); DBG_ASSERT(maxpData);
maxp->version = *((Fixed*)maxpData); maxpData+=4; SwapEndian(&maxp->version); maxp->numGlyphs = *((uint16*)maxpData); maxpData+=2; SwapEndian(&maxp->numGlyphs); maxp->maxPoints = *((uint16*)maxpData); maxpData+=2; SwapEndian(&maxp->maxPoints); maxp->maxContours = *((uint16*)maxpData); maxpData+=2; SwapEndian(&maxp->maxContours);
maxp->maxComponentPoints = *((uint16*)maxpData); maxpData+=2; SwapEndian(&maxp->maxComponentPoints); maxp->maxComponentContours = *((uint16*)maxpData); maxpData+=2; SwapEndian(&maxp->maxComponentContours); maxp->maxZones = *((uint16*)maxpData); maxpData+=2; SwapEndian(&maxp->maxZones); maxp->maxTwilightPoints = *((uint16*)maxpData); maxpData+=2; SwapEndian(&maxp->maxTwilightPoints); maxp->maxStorage = *((uint16*)maxpData); maxpData+=2; SwapEndian(&maxp->maxStorage);
maxp->maxFunctionDefs = *((uint16*)maxpData); maxpData+=2; SwapEndian(&maxp->maxFunctionDefs); maxp->maxInstructionDefs = *((uint16*)maxpData); maxpData+=2; SwapEndian(&maxp->maxInstructionDefs); maxp->maxStackElements = *((uint16*)maxpData); maxpData+=2; SwapEndian(&maxp->maxStackElements);
maxp->maxSizeOfInstructions = *((uint16*)maxpData); maxpData+=2; SwapEndian(&maxp->maxSizeOfInstructions); maxp->maxComponentElements = *((uint16*)maxpData); maxpData+=2; SwapEndian(&maxp->maxComponentElements);
DBG_ASSERT(maxp->version == 0x00010000); // 0x00010000 if (version 1.0) DBG_ASSERT(maxp->maxZones == 2); // set to 2 }
/******************************************************************************/
void ReadHEAD(uchar8* data, stTTF* ttf, stHEAD* head) { uchar8* headData = GetTableData(data, ttf, "head"); DBG_ASSERT(headData);
head->version = *((Fixed*)headData); headData+=4; SwapEndian(&head->version); head->fontRevision = *((Fixed*)headData); headData+=4; SwapEndian(&head->fontRevision); head->checkSumAdjustment = *((uint32*)headData); headData+=4; SwapEndian(&head->checkSumAdjustment); head->magicNumber = *((uint32*)headData); headData+=4; SwapEndian(&head->magicNumber); head->flags = *((uint16*)headData); headData+=2; SwapEndian(&head->flags); head->unitsPerEm = *((uint16*)headData); headData+=2; SwapEndian(&head->unitsPerEm);
DBG_ASSERT(sizeof(longDateTime)==8); head->created = *((uint16*)headData); headData+=8; //SwapEndian(&head->created); head->modified = *((uint16*)headData); headData+=8; //SwapEndian(&head->modified);
head->xMin = *((FWord*)headData); headData+=2; SwapEndian(&head->xMin); head->yMin = *((FWord*)headData); headData+=2; SwapEndian(&head->yMin); head->xMax = *((FWord*)headData); headData+=2; SwapEndian(&head->xMax); head->yMax = *((FWord*)headData); headData+=2; SwapEndian(&head->yMax); head->macStyle = *((uint16*)headData); headData+=2; SwapEndian(&head->macStyle);
head->lowestRecPPEM = *((uint16*)headData); headData+=2; SwapEndian(&head->lowestRecPPEM); head->fontDirectionHint = *((int16*)headData); headData+=2; SwapEndian(&head->fontDirectionHint);
head->indexToLocFormat = *((int16*)headData); headData+=2; SwapEndian(&head->indexToLocFormat); head->glyphDataFormat = *((int16*)headData); headData+=2; SwapEndian(&head->glyphDataFormat);
DBG_ASSERT(head->version == 0x00010000); // 0x00010000 if (version 1.0) DBG_ASSERT(head->magicNumber == 0x5F0F3CF5); // set to 0x5F0F3CF5 DBG_ASSERT(head->indexToLocFormat==0 || head->indexToLocFormat==1); // 0 for short offsets, 1 for long }
/******************************************************************************/
void ReadTTF(const char* szFileName, stTTF* ttf) { dprintf("Reading TTF File :%s\n", szFileName);
FILE * fp = fopen(szFileName, "rb"); DBG_ASSERT(fp);
int fileSize = FileSize(fp); dprintf("FileSize: %d Bytes\n", fileSize);
ReadFontDirectory(fp, &ttf->m_fontDirectory);
uchar8* data = new uchar8[fileSize + 100]; //+100 is safetly buffer DBG_ASSERT(data); fseek(fp, 0, SEEK_SET); fread(data, fileSize, 1, fp); fclose (fp);
ReadCMAP(data, ttf, &ttf->m_cmap); ReadHEAD(data, ttf, &ttf->m_head); ReadMAXP(data, ttf, &ttf->m_maxp); ReadLOCA(data, ttf, &ttf->m_loca); ReadGLYF(data, ttf, &ttf->m_glyf);
//DebugDrawGlyf(ttf);
delete[] data; }
/******************************************************************************/
|