]> Shamusworld >> Repos - ttedit/blobdiff - src/ttf.cpp
Fix zoom to zoom in/out from the center.
[ttedit] / src / ttf.cpp
old mode 100755 (executable)
new mode 100644 (file)
index 1244687..c8e6e7f
-//\r
-// TTF.CPP - The TrueType class\r
-// by James L. Hammons\r
-// (C) 2005 Underground Software\r
-//\r
-// This class encapsulates all the complexity of a TrueType Font File\r
-// database.  Included are functions to load, save, & initialize the\r
-// TTF database, move, add, & delete points & glyphs, i.e. manipulate\r
-// a TTF file in just about any way imaginable!\r
-//\r
-// JLH = James L. Hammons <jlhamm@acm.org>\r
-//\r
-// Who  When        What\r
-// ---  ----------  -------------------------------------------------------------\r
-// JLH  ??/??/199?  Created this file\r
-//\r
-//\r
-// STILL TO BE DONE:\r
-//\r
-// - Eliminate ALL references to BYTE, WORD, SBYTE, SWORD, etc.\r
-//\r
-\r
-#include <stdio.h>                                                             // For file handling, etc.                                                                                              //\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include "charnames.h"\r
-#include "ttf.h"\r
-\r
-#define TTFDEBUG\r
-\r
-#ifdef TTFDEBUG\r
-#include "debug.h"\r
-#endif\r
-\r
-#define NUMTABS  24                   // Number of distinct tables\r
-\r
-\r
-/*void fskip(HANDLE file, uint32 bytesToSkip)\r
-{\r
-       SetFilePointer(file, (LONG)bytesToSkip, NULL, FILE_CURRENT);\r
-}*/\r
-\r
-//\r
-// Get a BYTE from the current file...\r
-//\r
-uint8 ReadByte(FILE * file)\r
-{\r
-       return (uint8)fgetc(file);\r
-}\r
-\r
-// The following routines get and put WORDs and DWORDs in little endian\r
-// format, so they should work no matter what endianess the platform that\r
-// holds the TTF object.\r
-\r
-//\r
-// Get a WORD from the current file...\r
-//\r
-uint16 ReadWord(FILE * file)\r
-{\r
-       uint16 word = (uint16)fgetc(file) << 8;\r
-       word |= (uint16)fgetc(file);\r
-\r
-       return word;\r
-}\r
-\r
-//\r
-// Get a double WORD from the current file...\r
-//\r
-uint32 ReadDWord(FILE * file)\r
-{\r
-       uint32 dword = 0;\r
-\r
-       for(int i=0; i<4; i++)\r
-       {\r
-               dword <<= 8;\r
-               dword |= (uint8)fgetc(file);\r
-       }\r
-\r
-       return dword;\r
-}\r
-\r
-//\r
-// Write a WORD to the current file...\r
-//\r
-void WriteWord(FILE * file, uint16 word)\r
-{\r
-       fputc(word >> 8, file);                                         // Hi byte\r
-       fputc(word & 0xFF, file);                                       // Lo byte\r
-}\r
-\r
-//\r
-// Write a double WORD to the current file...\r
-//\r
-void WriteDWord(FILE * file, uint32 dword)\r
-{\r
-       for(int i=0; i<4; i++)\r
-       {\r
-               fputc((char)(dword >> 24), file);\r
-               dword <<= 8;\r
-       }\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Table extraction helper routines (inline 'em?)\r
-////////////////////////////////////////////////////////////////////////////\r
-\r
-//\r
-// Return a BYTE from a BYTE based table\r
-//\r
-uint8 GetByte(uint8 * table, uint32 &ptr)\r
-{\r
-       return table[ptr++];\r
-}\r
-\r
-//\r
-// Return a WORD from a BYTE based table\r
-//\r
-uint16 GetWord(uint8 * table, uint32 &ptr)\r
-{\r
-       uint16 hi = table[ptr++];\r
-       uint16 lo = table[ptr++];\r
-\r
-       return (uint16)((hi<<8) | lo);\r
-}\r
-\r
-//\r
-// Return a double WORD from a BYTE based table\r
-//\r
-uint32 GetDWord(uint8 * table, uint32 &ptr)\r
-{\r
-       uint32 hi1 = table[ptr++];\r
-       uint32 lo1 = table[ptr++];\r
-       uint32 hi2 = table[ptr++];\r
-       uint32 lo2 = table[ptr++];\r
-\r
-       return (uint32)((hi1 << 24) | (lo1 << 16) | (hi2 << 8) | lo2);\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Table storage helper routines (inline 'em?)\r
-////////////////////////////////////////////////////////////////////////////\r
-\r
-//\r
-// Store a BYTE in a BYTE based table\r
-//\r
-void SetByte(uint8 * table, uint32 &ptr, uint8 data)\r
-{\r
-       table[ptr++] = data;\r
-}\r
-\r
-//\r
-// Store a WORD in a BYTE based table\r
-//\r
-void SetWord(uint8 * table, uint32 &ptr, uint16 data)\r
-{\r
-       table[ptr++] = data>>8;  table[ptr++] = data&0xFF;\r
-}\r
-\r
-//\r
-// Store a DWORD in a BYTE based table\r
-//\r
-void SetDWord(uint8 * table, uint32 &ptr, uint32 data)\r
-{\r
-       table[ptr++] = (uint8)(data >> 24); table[ptr++] = (uint8)(data >> 16);\r
-       table[ptr++] = (uint8)(data >> 8);  table[ptr++] = (uint8)(data & 0xFF);\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Fixed point to float (& vice versa) conversions\r
-/////////////////////////////////////////////////////////////////////////////\r
-float FixedToFloat(int16 fixed)\r
-{\r
-       return (float)fixed / 16384.0f;\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// TTF Constructor\r
-/////////////////////////////////////////////////////////////////////////////\r
-TTF::TTF(void)\r
-{\r
-       loaded = false;                                                         // Set font initializer\r
-       isDirty = false;                                                        // Glyphs are clean\r
-       numberOfPolys = 0;                                                      // Set reasonable values\r
-       isCompositeGlyph = false;                                       // No composite glyph (yet)\r
-\r
-       parray[0] = &EBDT;  parray[1] = &EBLC;  parray[2] = &EBSC; // Init pointer\r
-       parray[3] = &LTSH;  parray[4] = &OS_2;  parray[5] = &PCLT; // array...\r
-       parray[6] = &VDMX;  parray[7] = &cmap;  parray[8] = &cvt; \r
-       parray[9] = &fpgm;  parray[10] = &gasp; parray[11] = &glyf;\r
-       parray[12] = &hdmx; parray[13] = &head; parray[14] = &hhea;\r
-       parray[15] = &hmtx; parray[16] = &kern; parray[17] = &loca;\r
-       parray[18] = &maxp; parray[19] = &name; parray[20] = &post;\r
-       parray[21] = &prep; parray[22] = &vhea; parray[23] = &vmtx;\r
-\r
-       larray[0] = &EBDT_len;  larray[1] = &EBLC_len;  larray[2] = &EBSC_len;\r
-       larray[3] = &LTSH_len;  larray[4] = &OS_2_len;  larray[5] = &PCLT_len;\r
-       larray[6] = &VDMX_len;  larray[7] = &cmap_len;  larray[8] = &cvt_len;\r
-       larray[9] = &fpgm_len;  larray[10] = &gasp_len; larray[11] = &glyf_len;\r
-       larray[12] = &hdmx_len; larray[13] = &head_len; larray[14] = &hhea_len;\r
-       larray[15] = &hmtx_len; larray[16] = &kern_len; larray[17] = &loca_len;\r
-       larray[18] = &maxp_len; larray[19] = &name_len; larray[20] = &post_len;\r
-       larray[21] = &prep_len; larray[22] = &vhea_len; larray[23] = &vmtx_len;\r
-\r
-       for(uint32 i=0; i<NUMTABS; i++)\r
-               *parray[i] = NULL;                                              // Init pointers...\r
-\r
-       for(uint32 i=0; i<MAXGLYPHS; i++)\r
-               glyph[i] = NULL;\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// TTF Destructor\r
-/////////////////////////////////////////////////////////////////////////////\r
-TTF::~TTF()\r
-{\r
-       ClearTables();                                                          // This should handle deallocation correctly...\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Member function: void Init(void)\r
-//\r
-// This function initializes the TTF object, setting reasonable values for\r
-// the various internal variables used by the object.\r
-// [distinct from New?]\r
-/////////////////////////////////////////////////////////////////////////////\r
-void TTF::Init(void)\r
-{\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Clear the tables so that file can be reloaded\r
-/////////////////////////////////////////////////////////////////////////////\r
-void TTF::ClearTables(void)\r
-{\r
-       for(uint32 i=0; i<NUMTABS; i++)\r
-       {\r
-               if ((*parray[i]) != NULL)\r
-               {\r
-                       free(*parray[i]);\r
-                       *parray[i] = NULL;\r
-                       *larray[i] = 0;\r
-               }\r
-       }  \r
-\r
-       for(uint32 i=0; i<MAXGLYPHS; i++)\r
-       {\r
-               if (glyph[i] != NULL)\r
-               {\r
-                       free(glyph[i]);\r
-                       glyph[i] = NULL;\r
-               }\r
-       }\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Member function: BOOL Load(const char * filename)\r
-//\r
-// This loads the TTF database from an external file.  Returns 'true' if\r
-// successful.\r
-/////////////////////////////////////////////////////////////////////////////\r
-bool TTF::Load(const char * filename)\r
-{\r
-//     unsigned char ch;                                                       // Temp variable\r
-//     UINT num_tabs;                                                          // Number of tables\r
-       uint32 offset[NUMTABS], length[NUMTABS];        // Temporary storage...\r
-       char names[NUMTABS][5];\r
-       char narray[NUMTABS][5] = { "EBDT", "EBLC", "EBSC", "LTSH", "OS/2", "PCLT",\r
-               "VDMX", "cmap", "cvt ", "fpgm", "gasp", "glyf", "hdmx", "head", "hhea",\r
-               "hmtx", "kern", "loca", "maxp", "name", "post", "prep", "vhea", "vmtx" };\r
-\r
-       //loaded = false;\r
-//     file.open(filename, ios::binary|ios::in);       // Open the file\r
-       FILE * file = fopen(filename, "rb");\r
-\r
-       if (file == NULL)\r
-#ifdef TTFDEBUG\r
-{\r
-WriteLogMsg("Failed to open file!\n");\r
-#endif\r
-               return false;\r
-#ifdef TTFDEBUG\r
-}\r
-#endif\r
-\r
-       if (ReadDWord(file) != 0x00010000)\r
-#ifdef TTFDEBUG\r
-{\r
-WriteLogMsg("File was NOT a TTF file!\n");\r
-#endif\r
-               return false;                                                   // Not a TTF file...\r
-#ifdef TTFDEBUG\r
-}\r
-#endif\r
-\r
-       uint32 num_tabs = ReadWord(file);                       // Get # of tables\r
-#ifdef TTFDEBUG\r
-WriteLogMsg("Number of tables is %u...\n", num_tabs);\r
-#endif\r
-//     fskip(file, 6);                                                         // Skip this shiat...\r
-       fseek(file, 6, SEEK_CUR);\r
-\r
-#ifdef TTFDEBUG\r
-WriteLogMsg("Reading names of tables...\n");\r
-#endif\r
-       for(uint32 i=0; i<num_tabs; i++)\r
-       {\r
-//             ReadFile(file, names[i], 4, &bytesRead, NULL);\r
-               fread(names[i], 1, 4, file);\r
-               names[i][4] = 0;\r
-//             fskip(file, 4);                                                 // Checksum\r
-               fseek(file, 4, SEEK_CUR);                               // Checksum\r
-               offset[i] = ReadDWord(file);                    // Offset from start of file\r
-               length[i] = ReadDWord(file);                    // Length of table\r
-       }\r
-\r
-#ifdef TTFDEBUG\r
-WriteLogMsg("Reading tables...\n");\r
-#endif\r
-       for(uint32 i=0; i<num_tabs; i++)\r
-       {\r
-               for(uint32 j=0; j<NUMTABS; j++)\r
-               {\r
-                       if ((strcmp(names[i], narray[j])) == 0) // Found a match...\r
-                       {\r
-//                             *parray[j] = (uint8 *)GlobalAlloc(GMEM_FIXED, length[i]);       // Allocate space\r
-                               *parray[j] = (uint8 *)malloc(length[i]); // Alloc space\r
-\r
-                               if (*parray[j] == NULL)\r
-                                       return false;                           // Bail out if nothing allocated\r
-\r
-                               *larray[j] = length[i];                 // Set its length...\r
-//                             SetFilePointer(file, (LONG)offset[i], NULL, FILE_BEGIN);\r
-//                             ReadFile(file, *parray[j], length[i], &bytesRead, NULL);\r
-                               fseek(file, offset[i], SEEK_SET);\r
-                               fread(*parray[j], 1, length[i], file);\r
-                               break;\r
-                       }\r
-               }\r
-       }\r
-\r
-       fclose(file);\r
-\r
-// This shouldn't be necessary, since it's irrelevant (loaded flag)\r
-//    loaded = true;                       // Set 'loaded' flag...\r
-    isDirty = false;                     // Glyphs are clean\r
-    ExtractTables();                     // Move table data to my structs\r
-                                         // & ignore return val\r
-                                         // (should handle errors here)\r
-       return true;\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Member function: BOOL Save(const char * filename)\r
-//\r
-// Save the TT font currently in the object\r
-/////////////////////////////////////////////////////////////////////////////\r
-bool TTF::Save(const char * filename)\r
-{\r
-//  fstream file;\r
-//     ULONG offset = 12;\r
-       uint32 numtabs = 0;\r
-       char padding[3] = { 0, 0, 0 };\r
-       // Convert this to a table of ULONGs to decrease complexity...\r
-//wouldn't be endian safe then...\r
-       char narray[NUMTABS][5] = { "EBDT", "EBLC", "EBSC", "LTSH", "OS/2", "PCLT",\r
-               "VDMX", "cmap", "cvt ", "fpgm", "gasp", "glyf", "hdmx", "head", "hhea",\r
-               "hmtx", "kern", "loca", "maxp", "name", "post", "prep", "vhea", "vmtx" };\r
-\r
-       if (isDirty)\r
-               EncodeGlyph(currentGlyph);\r
-\r
-       BuildTables();                                                          // Ignore return value...  \r
-\r
-       for(uint32 i=0; i<NUMTABS; i++)                         // Figure out how many tables there are\r
-               if ((*parray[i]) != NULL)\r
-                       numtabs++;\r
-\r
-       uint32 offset = 12 + (numtabs * 16);            // Calc correct offset to start of data\r
-\r
-//     HANDLE file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,\r
-//             NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);\r
-       FILE * file = fopen(filename, "wb");\r
-\r
-       WriteDWord(file, 0x00010000);                           // Write header...\r
-       WriteWord(file, numtabs);\r
-       WriteWord(file, 0);                                                     // SearchRange (Max power of 2 <= numTables) x 16.\r
-       WriteWord(file, 0);                                                     // entrySelector Log2(max power of 2 <= numTables).\r
-       WriteWord(file, 0);                                                     // NumTables x 16 - searchRange.\r
-\r
-       for(uint32 i=0; i<NUMTABS; i++)                                 // Write out table directory...\r
-       {\r
-               if ((*parray[i]) != NULL)\r
-               {\r
-//                     for(int j=0; j<4; j++)\r
-//                             file.put(narray[i][j]);                 // Name\r
-//                     WriteFile(file, narray[i], 4, &bytesWritten, NULL);\r
-                       fwrite(narray[i], 1, 4, file);          // Name\r
-\r
-                       WriteDWord(file, 0);                            // Checksum\r
-                       WriteDWord(file, offset);                       // Offset\r
-                       WriteDWord(file, (*larray[i]));         // Length\r
-\r
-                       offset += (((*larray[i]) + 3) & ~3);    // Pad out to 4-uint8 boundary...\r
-               }\r
-       }\r
-\r
-       for(uint32 i=0; i<NUMTABS; i++)                                 // Write out the tables...\r
-       {\r
-               if ((*parray[i]) != NULL)\r
-               {\r
-//                     for(uint32 j=0; j<(*larray[i]); j++)\r
-//                             file.put((*parray[i])[j]);\r
-//                     WriteFile(file, *parray[i], *larray[i], &bytesWritten, NULL);\r
-                       fwrite(*parray[i], 1, *larray[i], file);\r
-\r
-                       uint32 remainder = ((*larray[i]) & 0x3);\r
-                       if (remainder)               // i.e., it's not evenly div by 4\r
-//                             for(j=remainder; j<4; j++)\r
-//                                     file.put((char)0);       // pad it!\r
-//                             WriteFile(file, padding, 4 - remainder, &bytesWritten, NULL);\r
-                               fwrite(padding, 1, 4 - remainder, file);\r
-               }\r
-       }\r
-\r
-       fclose(file);\r
-\r
-       return true;                                                            // Whether or not it was successful...\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Member function: BOOL EncodeGlyph(int glyphnum)\r
-//\r
-// This function encodes the glyph data and stores it to the 'glyf' table.\r
-/////////////////////////////////////////////////////////////////////////////\r
-bool TTF::EncodeGlyph(uint16 glyphnum)\r
-{\r
-       bool retval = false;                                            // Assume failure\r
-       uint8 flag, xbuf[4000], ybuf[4000], fbuf[2000];\r
-       uint32 xp = 0, yp = 0, fp = 0;                          // Table pointers\r
-\r
-       if (glyphnum < myMaxp.numGlyphs)  // numofgls is 1 based ind, glyph# 0 based\r
-       {\r
-               // need to add composite encoding...\r
-               int lastx = 0, lasty = 0;\r
-\r
-               for(uint32 i=0; i<numberOfPoints; i++)\r
-               {\r
-                       flag = 0;\r
-                       int curx = gx[i] - lastx, cury = gy[i] - lasty;\r
-\r
-                       if (onCurve[i])\r
-                               flag |= 0x01;                                   // Set on curve info\r
-\r
-                       if (curx)\r
-                       {\r
-                               if ((curx > 255) || (curx < -255)) // I.e., it's 2 uint8 value\r
-                                       SetWord(xbuf, xp, curx);\r
-                               else\r
-                               {\r
-                                       if (curx & 0x100)\r
-                                       {\r
-                                               flag |= 0x02; // I.e., it's negative\r
-                                               curx *= -1;   // Flip it so correct value is stored\r
-                                       }\r
-                                       else\r
-                                               flag |= 0x12;\r
-\r
-                                       SetByte(xbuf, xp, curx);        // Automagically strips neg bit\r
-                               }\r
-                       }\r
-                       else\r
-                               flag |= 0x10;                                   // X-coord is same...\r
-  \r
-                       if (cury)\r
-                       {\r
-                               if ((cury > 255) || (cury < -255)) // I.e., it's 2 uint8 value\r
-                                       SetWord(ybuf, yp, cury);\r
-                               else\r
-                               {\r
-                                       if (cury & 0x100)\r
-                                       {\r
-                                               flag |= 0x04; // I.e., it's negative\r
-                                               cury *= -1;\r
-                                       }\r
-                                       else\r
-                                               flag |= 0x24;\r
-            \r
-                                       SetByte(ybuf, yp, cury);\r
-                               }\r
-                       }\r
-                       else\r
-                               flag |= 0x20;                 // Y-coord is same...\r
-  \r
-                       fbuf[i] = flag;\r
-                       lastx = gx[i];  lasty = gy[i];\r
-               }\r
-\r
-               // Now crunch flags...  ugly, ugly, ugly.\r
-/*\r
-    fbuf[numberOfPoints] = 0;  // Set sentinel value (ugly way to do this)\r
-    for(i=0; i<numberOfPoints; i++);\r
-    {\r
-      if (fbuf[i] == fbuf[i+1])  // \r
-      {\r
-        uint8 count = 0;  // Sentinel takes care of check for end of flags...\r
-        while (fbuf[i] == fbuf[++i])  count++; // Count number of repeats\r
-        i--;\r
-        fbuf[fp++] = fbuf[i] | 0x08; // Set repeat flag\r
-        fbuf[fp++] = count;          // & number of repeats\r
-      }\r
-      else  fbuf[fp++] = fbuf[i];    // Otherwise, just copy...\r
-    }\r
-*/\r
-               fp = numberOfPoints;\r
-               // Find length of glyph and reallocate space if necessary\r
-\r
-               uint32 newLength = 12 + numberOfPolys*2 + numberOfHints + fp + xp + yp;\r
-\r
-               if (newLength & 0x03)\r
-                       newLength += (4 - newLength & 0x03);\r
-\r
-               if (glyphLen[glyphnum] != newLength)\r
-               {\r
-                       glyph[glyphnum] = (uint8 *)realloc(glyph[glyphnum], newLength);\r
-                       glyphLen[glyphnum] = newLength;\r
-               }\r
-\r
-               // And finally, store it!\r
-\r
-               uint32 gp = 0;                                                  // Glyph pointer...\r
-               SetWord(glyph[glyphnum], gp, numberOfPolys);\r
-               SetWord(glyph[glyphnum], gp, llx);\r
-               SetWord(glyph[glyphnum], gp, lly);\r
-               SetWord(glyph[glyphnum], gp, urx);\r
-               SetWord(glyph[glyphnum], gp, ury);\r
-               for(uint32 i=0; i<numberOfPolys; i++)\r
-                       SetWord(glyph[glyphnum], gp, poly[i]);\r
-               SetWord(glyph[glyphnum], gp, numberOfHints);\r
-               for(uint32 i=0; i<numberOfHints; i++)\r
-                       SetByte(glyph[glyphnum], gp, hint[i]);\r
-               for(uint32 i=0; i<fp; i++)\r
-                       SetByte(glyph[glyphnum], gp, fbuf[i]);\r
-               for(uint32 i=0; i<xp; i++)\r
-                       SetByte(glyph[glyphnum], gp, xbuf[i]);\r
-               for(uint32 i=0; i<yp; i++)\r
-                       SetByte(glyph[glyphnum], gp, ybuf[i]);\r
-\r
-               retval = true;                                                  // Successfully encoded!\r
-       }\r
-\r
-       return retval;\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Member function: BOOL DecodeGlyph(int glyphnum)\r
-//\r
-// This function decodes the glyph data and stores it to the object's\r
-// internal array.\r
-/////////////////////////////////////////////////////////////////////////////\r
-bool TTF::DecodeGlyph(uint16 glyphnum)\r
-{\r
-       bool retval = false;\r
-       uint32 i, dp;\r
-\r
-       // glyphnum is 0 based index, while numGlyphs is 1 based\r
-       if (glyphnum >= myMaxp.numGlyphs)\r
-               return false;  // Invalid char #\r
-\r
-       if (!glyphLen[glyphnum])\r
-       {\r
-               numberOfPoints = numberOfPolys = 0;\r
-               return true;                                                    // Zero length IS valid...\r
-       }\r
-//     else                                                                            // Get character data...\r
-//     {\r
-    // Now get the character data...\r
-       dp = 0;                     // Reset data pointer\r
-       isCompositeGlyph = false;   // Default is no\r
-       numberOfPolys = GetWord(glyph[glyphnum], dp);  // # of polygons\r
-\r
-       llx = (int16)GetWord(glyph[glyphnum], dp);           // Lower left X\r
-       lly = (int16)GetWord(glyph[glyphnum], dp);           // Lower left Y\r
-       urx = (int16)GetWord(glyph[glyphnum], dp);           // Upper right X\r
-       ury = (int16)GetWord(glyph[glyphnum], dp);           // Upper right Y\r
-\r
-       // Need to handle composite glyphs better here.  The ways things\r
-       // are set now is a recipe for disaster...\r
-\r
-       if (numberOfPolys == 0xFFFF)\r
-       {\r
-               isCompositeGlyph = true;\r
-               numberOfPolys = 0;                                              // Set for no points\r
-\r
-               Composite cmpst;\r
-\r
-               while (!compositeList.IsEmpty())                // Empty composite list...\r
-                       compositeList.GetFront();\r
-\r
-               do\r
-               {\r
-                       cmpst.flags = GetWord(glyph[glyphnum], dp);\r
-                       cmpst.glyphIndex = GetWord(glyph[glyphnum], dp);\r
-                       cmpst.arg1 = (cmpst.flags & 0x01 ? (int16)GetWord(glyph[glyphnum], dp) : (int8)GetByte(glyph[glyphnum], dp));\r
-                       cmpst.arg2 = (cmpst.flags & 0x01 ? (int16)GetWord(glyph[glyphnum], dp) : (int8)GetByte(glyph[glyphnum], dp));\r
-\r
-                       if (cmpst.flags & 0x08)\r
-                               cmpst.xScale = cmpst.yScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp));\r
-                       else if (cmpst.flags & 0x40)\r
-                               cmpst.xScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp)),\r
-                               cmpst.yScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp));\r
-                       else if (cmpst.flags & 0x80)\r
-                               cmpst.xScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp)),\r
-                               cmpst.scale01 = FixedToFloat((int16)GetWord(glyph[glyphnum], dp)),\r
-                               cmpst.scale10 = FixedToFloat((int16)GetWord(glyph[glyphnum], dp)),\r
-                               cmpst.yScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp));\r
-\r
-                       compositeList.AddAtRear(cmpst);\r
-               }\r
-               while (cmpst.flags & 0x20); //*/\r
-\r
-               return true;\r
-       }\r
-\r
-//do {\r
-//     USHORT flags;\r
-//     USHORT glyphIndex;\r
-//     if ( flags & ARG_1_AND_2_ARE_uint16S) {\r
-//     (SHORT or Fuint16) argument1;\r
-//     (SHORT or Fuint16) argument2;\r
-//     } else {\r
-//             USHORT arg1and2; /* (arg1 << 8) | arg2 */\r
-//     }\r
-//     if ( flags & WE_HAVE_A_SCALE ) {\r
-//             F2Dot14  scale;    /* Format 2.14 */\r
-//     } else if ( flags & WE_HAVE_AN_X_AND_Y_SCALE ) {\r
-//             F2Dot14  xscale;    /* Format 2.14 */\r
-//             F2Dot14  yscale;    /* Format 2.14 */\r
-//     } else if ( flags & WE_HAVE_A_TWO_BY_TWO ) {\r
-//             F2Dot14  xscale;    /* Format 2.14 */\r
-//             F2Dot14  scale01;   /* Format 2.14 */\r
-//             F2Dot14  scale10;   /* Format 2.14 */\r
-//             F2Dot14  yscale;    /* Format 2.14 */\r
-//     }\r
-//} while ( flags & MORE_COMPONENTS ) \r
-//if (flags & WE_HAVE_INSTR){\r
-//     USHORT numInstr\r
-//     uint8 instr[numInstr]\r
-//\r
-//Flags                    Bit     Description \r
-//ARG_1_AND_2_ARE_uint16S    0       If this is set, the arguments are uint16s;\r
-//                                 otherwise, they are uint8s.\r
-//ARGS_ARE_XY_VALUES       1       If this is set, the arguments are xy values;\r
-//                                 otherwise, they are points.\r
-//ROUND_XY_TO_GRID         2       For the xy values if the preceding is true.\r
-//WE_HAVE_A_SCALE          3       This indicates that there is a simple scale\r
-//                                 for the component. Otherwise, scale = 1.0.\r
-//RESERVED                 4       This bit is reserved.  Set it to 0. \r
-//MORE_COMPONENTS          5       Indicates at least one more glyph after this\r
-//                                 one.\r
-//WE_HAVE_AN_X_AND_Y_SCALE 6       The x direction will use a different scale\r
-//                                 from the y direction.\r
-//WE_HAVE_A_TWO_BY_TWO     7       There is a 2 by 2 transformation that will\r
-//                                 be used to scale the component.\r
-//WE_HAVE_INSTRUCTIONS     8       Following the last component are\r
-//                                 instructions for the composite character.\r
-//USE_MY_METRICS           9       If set, this forces the aw and lsb (and rsb)\r
-//                                 for the composite to be equal to those from\r
-//                                 this original glyph. This works for hinted\r
-//                                 and unhinted characters.\r
-\r
-       for(i=0; i<numberOfPolys; i++)\r
-               poly[i] = GetWord(glyph[glyphnum], dp);\r
-\r
-       numberOfHints = GetWord(glyph[glyphnum], dp);\r
-\r
-       for(i=0; i<numberOfHints; i++)\r
-               hint[i] = GetByte(glyph[glyphnum], dp);\r
-\r
-       // Decode the dots...\r
-\r
-       uint32 num_pts = poly[numberOfPolys-1] + 1;\r
-       numberOfPoints = num_pts; // necessary??\r
-       uint32 xptr, yptr;        // pointers to beginning of coord data\r
-       uint32 numXs = 0;\r
-       int xx = 0, yy = 0, repeat;\r
-       uint32 numTokens = num_pts, k, numRep;\r
-\r
-       // We make an educated guess that num_pts = num_tokens; but if there\r
-       // is repeated data in the tokens, then we need to adjust the # of\r
-       // tokens down appropriately.\r
-\r
-       for(uint32 i=0; i<numTokens; i++)\r
-       {\r
-               uint8 token = glyph[glyphnum][dp+i];  uint32 rpts = 1;\r
-\r
-               if (token & 0x08)      // Repeated token?\r
-               {\r
-                       i++;                 // Yes, bump pointer to # of times to repeat\r
-                       numRep = glyph[glyphnum][dp+i];\r
-                       rpts += numRep;\r
-\r
-                       if (numRep > 1)      // Do we need to adjust numTokens?\r
-   // this is bad, modifying numTokens while it's used as a compare value\r
-   // in the above loop...\r
-   // Is it necessary to do so in order to keep from going too far?\r
-                       numTokens -= (numRep - 1); // Yes, adjust.\r
-               }\r
-\r
-               // 10 = same x(0uint8s), 00 = 2uint8s, 02&12 = 1uint8\r
-               if ((token & 0x02) == 0x02)\r
-                       numXs += rpts;\r
-\r
-               if ((token & 0x12) == 0x00)\r
-                       numXs += (rpts*2);\r
-       }\r
-\r
-       xptr = dp + numTokens;\r
-       yptr = dp + numTokens + numXs;\r
-\r
-       // & continue decoding X/Y-coords...\r
-\r
-       k = 0;                               // Index to the point array\r
-\r
-       for(uint32 i=0; i<numTokens; i++)\r
-       {\r
-               uint8 token = glyph[glyphnum][dp+i];\r
-               repeat = 1;\r
-\r
-               if (token & 0x08)\r
-               {\r
-                       i++;\r
-                       repeat += glyph[glyphnum][dp+i]; // Set repeat data...\r
-               }\r
-\r
-               while (repeat--)\r
-               {\r
-                       if ((token & 0x12) == 0x12)\r
-                               xx += GetByte(glyph[glyphnum], xptr);\r
-\r
-                       if ((token & 0x12) == 0x02)\r
-                               xx -= GetByte(glyph[glyphnum], xptr);\r
-\r
-                       if ((token & 0x12) == 0x00)\r
-                               xx += (int16)GetWord(glyph[glyphnum], xptr);\r
-\r
-                       gx[k] = xx;                      // Store x-coordinate\r
-\r
-                       if ((token & 0x24) == 0x24)\r
-                               yy += GetByte(glyph[glyphnum], yptr);\r
-\r
-                       if ((token & 0x24) == 0x04)\r
-                               yy -= GetByte(glyph[glyphnum], yptr);\r
-\r
-                       if ((token & 0x24) == 0x00)\r
-                               yy += (int16)GetWord(glyph[glyphnum], yptr);\r
-\r
-                       gy[k] = yy;                      // Store y-coordinate\r
-\r
-                       onCurve[k++] = (token & 0x01 ? true : false);  // If bit 0 set, then it's on curve\r
-               }\r
-       }\r
-\r
-       retval = true;                                                  // Hmm. Successfully decoded a glyph...\r
-//     }\r
-\r
-       isDirty = false;  // do it here?\r
-\r
-       return retval;\r
-}\r
-\r
-/*****************************************************************************\r
- Member function:\r
-\r
- This function decodes the 'glyf' data for a non-composite (atomic) glyph and\r
- returns it as a GlyphPoints object. Helper function.\r
- *****************************************************************************/\r
-GlyphPoints TTF::GetGlyphPoints(uint16 glyphNum)\r
-{\r
-       if (DecodeGlyph(glyphNum))\r
-               return GlyphPoints(numberOfPoints, numberOfPolys, gx, gy, onCurve, poly);\r
-\r
-       return GlyphPoints();\r
-}\r
-\r
-/*****************************************************************************\r
- Member function:\r
-\r
- This function decodes the 'glyf' data for a composite glyph and returns\r
- it as a GlyphPoints object.\r
- *****************************************************************************/\r
-GlyphPoints TTF::GetAllCompositePoints(uint16 glyphNum)\r
-{\r
-//  int tmpGlyph = currentGlyph;\r
-  \r
-       DecodeGlyph(glyphNum);         // Check for composite-ness\r
-\r
-       if (!isCompositeGlyph)\r
-               return GlyphPoints();\r
-\r
-/*\r
-  for(int i=1; i<=pDoc->m_myFont.compositeList.Length(); i++)\r
-  {\r
-    TComposite cmpst = fnt->compositeList.PeekPosition(i);\r
-    fnt->SetGlyph(cmpst.glyphIndex);\r
-    if (cmpst.flags & 0x0002)\r
-      m_nXOffset = cmpst.arg1, m_nYOffset = cmpst.arg2;\r
-    ScanConvertSingleGlyph(pDC, nScanlines, nHorzLines, nXOffset, nYOffset);\r
-  }\r
-  fnt->SetGlyph(pDoc->character_num);\r
-*/\r
-\r
-       GlyphPoints retVal;\r
-\r
-       for(int i=1; i<=compositeList.Length(); i++)\r
-       {\r
-               Composite cmpst = compositeList.PeekPosition(i);\r
-    \r
-//    SetGlyph(cmpst.glyphIndex);\r
-//    if (cmpst.flags & 0x0002)\r
-//      m_nXOffset = cmpst.arg1, m_nYOffset = cmpst.arg2;\r
-//    ScanConvertSingleGlyph(pDC, nScanlines, nHorzLines, nXOffset, nYOffset);\r
-               GlyphPoints gp = GetGlyphPoints(cmpst.glyphIndex);\r
-\r
-               if (cmpst.flags & 0x0002)\r
-                       gp.OffsetPoints(cmpst.arg1, cmpst.arg2);\r
-\r
-               retVal = retVal + gp;\r
-               // NOTE: May have to adjust scanlines as per 0x0002 above...\r
-       }\r
-\r
-//  SetGlyph(tmpGlyph);\r
-       DecodeGlyph(currentGlyph);     // Reset needed here...\r
-\r
-       return retVal;\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Member function: void GetCharName(int cNum, uint8 * buf)\r
-//\r
-// This function returns the character name of the glyph number passed in.\r
-/////////////////////////////////////////////////////////////////////////////\r
-void TTF::GetCharName(int cNum, uint8 * buf)\r
-{\r
-       buf[0] = 0;                                                                     // Set failure as default condition\r
-  \r
-       if (!post)                                                                      // PS names are here...\r
-               return;\r
-\r
-       if (post[1] != 0x02 || post[2] != 0x00)         // i.e., it's NOT a V2.0 table\r
-               return;\r
-\r
-       uint8 * pTab = NULL;\r
-       uint32 tabOff = 34, numGlyphs = (uint32)((post[32] << 8) | post[33]);\r
-       uint32 index = (uint32)((post[tabOff + cNum * 2] << 8) | post[tabOff + cNum * 2 + 1]);\r
-       uint32 nInd2;\r
-\r
-       if (index > 257)\r
-       {\r
-               index -= 258;\r
-               nInd2 = tabOff + (2 * numGlyphs);\r
-               pTab = post;\r
-       }\r
-       else\r
-       {\r
-               nInd2 = 0;\r
-               pTab = macStdNames;\r
-       }\r
-\r
-       for(uint32 i=0; i<index; i++)\r
-               nInd2 = nInd2 + pTab[nInd2] + 1; // 1st uint8 is length of string + that uint8\r
-\r
-       uint8 len = pTab[nInd2];\r
-       nInd2++;\r
-\r
-       for(uint8 i=0; i<len; i++)\r
-               buf[i] = pTab[nInd2 + i];\r
-\r
-       buf[len] = 0;\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Member function: BOOL ExtractTables(void)\r
-//\r
-// This function extracts the data from the various tables and puts them in\r
-// various structs for easier handling of the font data.\r
-/////////////////////////////////////////////////////////////////////////////\r
-bool TTF::ExtractTables(void)\r
-{\r
-       if (head_len != 54)\r
-       {\r
-#ifdef TTFDEBUG\r
-WriteLogMsg("Bad HEAD header: Expected 54, found %u...\n", head_len);\r
-#endif\r
-               return false;                                                   // Corrupt data?\r
-       }\r
-\r
-       uint32 tp = 0;\r
-       myHead.version            = GetDWord(head, tp);\r
-       myHead.fontRevision       = GetDWord(head, tp);\r
-       myHead.checkSumAdjustment = GetDWord(head, tp);\r
-       myHead.magicNumber        = GetDWord(head, tp);\r
-       myHead.flags              = GetWord(head, tp);\r
-       myHead.unitsPerEm         = GetWord(head, tp);\r
-       myHead.createdh           = GetDWord(head, tp);\r
-       myHead.createdl           = GetDWord(head, tp);\r
-       myHead.modifiedh          = GetDWord(head, tp);\r
-       myHead.modifiedl          = GetDWord(head, tp);\r
-       myHead.xMin               = GetWord(head, tp);\r
-       myHead.yMin               = GetWord(head, tp);\r
-       myHead.xMax               = GetWord(head, tp);\r
-       myHead.yMax               = GetWord(head, tp);\r
-       myHead.macStyle           = GetWord(head, tp);\r
-       myHead.lowestRecPPEM      = GetWord(head, tp);\r
-       myHead.fontDirectionHint  = (int16)GetWord(head, tp);\r
-       myHead.indexToLocFormat   = (int16)GetWord(head, tp);\r
-       myHead.glyphDataFormat    = (int16)GetWord(head, tp);\r
-\r
-       if (maxp_len != 32)\r
-       {\r
-#ifdef TDEBUG\r
-WriteLogMsg("Bad MAXP header: Expected 32, found %u...\n", maxp_len);\r
-#endif\r
-               return false;                                                   // Corrupt data?\r
-       }\r
-\r
-       tp = 0;                                                                         // Reset table pointer\r
-       myMaxp.version               = GetDWord(maxp, tp);\r
-       myMaxp.numGlyphs             = GetWord(maxp, tp);\r
-       myMaxp.maxPoints             = GetWord(maxp, tp);\r
-       myMaxp.maxContours           = GetWord(maxp, tp);\r
-       myMaxp.maxCompositePoints    = GetWord(maxp, tp);\r
-       myMaxp.maxCompositeContours  = GetWord(maxp, tp);\r
-       myMaxp.maxZones              = GetWord(maxp, tp);\r
-       myMaxp.maxTwilightPoints     = GetWord(maxp, tp);\r
-       myMaxp.maxStorage            = GetWord(maxp, tp);\r
-       myMaxp.maxFunctionDefs       = GetWord(maxp, tp);\r
-       myMaxp.maxInstructionDefs    = GetWord(maxp, tp);\r
-       myMaxp.maxStackElements      = GetWord(maxp, tp);\r
-       myMaxp.maxSizeOfInstructions = GetWord(maxp, tp);\r
-       myMaxp.maxComponentElements  = GetWord(maxp, tp);\r
-       myMaxp.maxComponentDepth     = GetWord(maxp, tp);\r
-\r
-       tp = 0;                                                                         // Reset table pointer\r
-       uint32 start = (myHead.indexToLocFormat ? GetDWord(loca, tp) : GetWord(loca, tp) << 1);\r
-\r
-       for(uint32 i=0; i<myMaxp.numGlyphs; i++)\r
-       {\r
-               uint32 end = (myHead.indexToLocFormat ? GetDWord(loca, tp) : GetWord(loca, tp) << 1);\r
-               uint32 length = end - start;\r
-               glyphLen[i] = length;                                   // Lengths are saved 'cause malloc is sloppy\r
-\r
-               if (length)     // loca+start? pointer arithmetic?\r
-               {\r
-                       glyph[i] = (uint8 *)malloc(length);     // Allocate space,\r
-                       memcpy(glyph[i], glyf+start, length);   // and move it!\r
-               }\r
-               else\r
-                       glyph[i] = NULL;\r
-\r
-               start = end;                                                    // Reset start value\r
-       }\r
-\r
-       return true;\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Member function: BOOL BuildTables(void)\r
-//\r
-// This function builds the various TTF tables using info in the various\r
-// structs so that a TTF file can be written out to disk.\r
-/////////////////////////////////////////////////////////////////////////////\r
-bool TTF::BuildTables(void)\r
-{\r
-       uint32 i, tp, start;\r
-\r
-       myHead.indexToLocFormat = 1;                            // We don't bother with [uint16s*2] format...\r
-\r
-       // Build HEAD table\r
-\r
-       tp = 0;                                                                         // Reset table pointer\r
-       SetDWord(head, tp, myHead.version);//            = GetDWord(head, tp);\r
-       SetDWord(head, tp, myHead.fontRevision);//       = GetDWord(head, tp);\r
-       SetDWord(head, tp, myHead.checkSumAdjustment);// = GetDWord(head, tp);\r
-       SetDWord(head, tp, myHead.magicNumber);//        = GetDWord(head, tp);\r
-       SetWord(head, tp, myHead.flags);//              = GetWord(head, tp);\r
-       SetWord(head, tp, myHead.unitsPerEm);//         = GetWord(head, tp);\r
-       SetDWord(head, tp, myHead.createdh);//           = GetDWord(head, tp);\r
-       SetDWord(head, tp, myHead.createdl);//           = GetDWord(head, tp);\r
-       SetDWord(head, tp, myHead.modifiedh);//          = GetDWord(head, tp);\r
-       SetDWord(head, tp, myHead.modifiedl);//          = GetDWord(head, tp);\r
-       SetWord(head, tp, myHead.xMin);//               = GetWord(head, tp);\r
-       SetWord(head, tp, myHead.yMin);//               = GetWord(head, tp);\r
-       SetWord(head, tp, myHead.xMax);//               = GetWord(head, tp);\r
-       SetWord(head, tp, myHead.yMax);//               = GetWord(head, tp);\r
-       SetWord(head, tp, myHead.macStyle);//           = GetWord(head, tp);\r
-       SetWord(head, tp, myHead.lowestRecPPEM);//      = GetWord(head, tp);\r
-       SetWord(head, tp, myHead.fontDirectionHint);//  = (int16)GetWord(head, tp);\r
-       SetWord(head, tp, myHead.indexToLocFormat);//   = (int16)GetWord(head, tp);\r
-       SetWord(head, tp, myHead.glyphDataFormat);//    = (int16)GetWord(head, tp);\r
-\r
-       // Build MAXP table\r
-\r
-       tp = 0;                                                                         // Reset table pointer\r
-       SetDWord(maxp, tp, myMaxp.version);//               = GetDWord(maxp, tp);\r
-       SetWord(maxp, tp, myMaxp.numGlyphs);//             = GetWord(maxp, tp);\r
-       SetWord(maxp, tp, myMaxp.maxPoints);//             = GetWord(maxp, tp);\r
-       SetWord(maxp, tp, myMaxp.maxContours);//           = GetWord(maxp, tp);\r
-       SetWord(maxp, tp, myMaxp.maxCompositePoints);//    = GetWord(maxp, tp);\r
-       SetWord(maxp, tp, myMaxp.maxCompositeContours);//  = GetWord(maxp, tp);\r
-       SetWord(maxp, tp, myMaxp.maxZones);//              = GetWord(maxp, tp);\r
-       SetWord(maxp, tp, myMaxp.maxTwilightPoints);//     = GetWord(maxp, tp);\r
-       SetWord(maxp, tp, myMaxp.maxStorage);//            = GetWord(maxp, tp);\r
-       SetWord(maxp, tp, myMaxp.maxFunctionDefs);//       = GetWord(maxp, tp);\r
-       SetWord(maxp, tp, myMaxp.maxInstructionDefs);//    = GetWord(maxp, tp);\r
-       SetWord(maxp, tp, myMaxp.maxStackElements);//      = GetWord(maxp, tp);\r
-       SetWord(maxp, tp, myMaxp.maxSizeOfInstructions);// = GetWord(maxp, tp);\r
-       SetWord(maxp, tp, myMaxp.maxComponentElements);//  = GetWord(maxp, tp);\r
-       SetWord(maxp, tp, myMaxp.maxComponentDepth);//     = GetWord(maxp, tp);\r
-\r
-       // Build LOCA & GLYF tables\r
-\r
-       loca_len = (myMaxp.numGlyphs+1) * 4;            // Set size of table\r
-\r
-       if (loca)\r
-               free(loca);                                                             // And create/reallocate it...\r
-\r
-       loca = (uint8 *) malloc(loca_len);\r
-\r
-       glyf_len = 0;                                                           // Refigure glyf table length\r
-\r
-       for(i=0; i<myMaxp.numGlyphs; i++)\r
-               glyf_len += glyphLen[i];\r
-\r
-       if (glyf)\r
-               free(glyf);\r
-\r
-       glyf = (uint8 *) malloc(glyf_len);\r
-\r
-       start = tp = 0;                                                         // Reset table pointer\r
-\r
-       for(i=0; i<myMaxp.numGlyphs; i++)\r
-       {\r
-               SetDWord(loca, tp, start);                              // Store glyph start address\r
-\r
-               if (glyphLen[i])\r
-                       memcpy(glyf+start, glyph[i], glyphLen[i]);\r
-\r
-               start += glyphLen[i];\r
-       }\r
-\r
-       SetDWord(loca, tp, start);                                      // Finally, store end of glyphs+1\r
-\r
-       return true;\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Member function: BOOL SetGlyph(int glyphnum)\r
-//\r
-// This function decodes the glyph data and stores the points in its own\r
-// internal array.  If the flag isDirty is set, it also encodes the internal\r
-// array and stores it to the 'glyf' table.\r
-/////////////////////////////////////////////////////////////////////////////\r
-bool TTF::SetGlyph(uint16 glyphnum)\r
-{\r
-       bool retval = false;                                            // Set failure as default\r
-\r
-       if (isDirty)\r
-               EncodeGlyph(currentGlyph);\r
-\r
-       isDirty = false;\r
-\r
-       if (glyphnum < myMaxp.numGlyphs)                        // numofgls is 1 based ind, glyph# 0 based\r
-       {\r
-               currentGlyph = glyphnum;\r
-               DecodeGlyph(currentGlyph);\r
-               retval = true;\r
-       }\r
-\r
-       return retval;\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Member function: BOOL AddGlyph(int glyphnum)\r
-//\r
-// This function adds a glyph of zero size at position glyphnum.  If glyphnum\r
-// is greater than the number of glyphs, glyph is added at end of list. This\r
-// glyph then becomes the current glyph.\r
-/////////////////////////////////////////////////////////////////////////////\r
-bool TTF::AddGlyph(uint16 glyphnum)\r
-{\r
-       // incomplete: JLH\r
-       bool retval = false;\r
-\r
-       if (isDirty)\r
-               EncodeGlyph(currentGlyph);\r
-\r
-       isDirty = false;\r
-\r
-       return retval;\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Member function: BOOL DeleteGlyph(int glyphnum)\r
-//\r
-// This function deletes the glyph at position glyphnum.  All glyphs after\r
-// this glyph are moved down in position.\r
-/////////////////////////////////////////////////////////////////////////////\r
-bool TTF::DeleteGlyph(uint16 glyphnum)\r
-{\r
-       // incomplete: JLH\r
-       bool retval = false;\r
-\r
-       return retval;\r
-}\r
-\r
-//\r
-// Various & sundry member functions implementation\r
-//\r
-// NOTE: For error handling, should throw exceptions--not return values...! !!! FIX !!!\r
-//\r
-\r
-Box TTF::GetBoundingBox(void)\r
-{\r
-       return Box(llx, lly, urx, ury);\r
-}\r
-\r
-GlyphPt TTF::GetPoint(uint16 pointno)\r
-{\r
-       GlyphPt p;\r
-\r
-       if (pointno >= MAXPOINTS)\r
-               return p; // Fix to make invalid\r
-\r
-       p.x = gx[pointno], p.y = gy[pointno], p.onCurve = onCurve[pointno];\r
-       return p;\r
-}\r
-\r
-uint16 TTF::GetNumberOfPolys(void)\r
-{\r
-       return numberOfPolys;\r
-}\r
-\r
-uint16 TTF::GetPolyEnd(uint16 polynum)\r
-{\r
-       if (polynum >= numberOfPolys)\r
-               return 0;\r
-\r
-       return poly[polynum];\r
-}\r
-\r
-int TTF::GetPointX(uint16 pointno)\r
-{\r
-       if (pointno >= MAXPOINTS)\r
-               return 0;\r
-\r
-       return gx[pointno];\r
-}\r
-\r
-int TTF::GetPointY(uint16 pointno)\r
-{\r
-       if (pointno >= MAXPOINTS)\r
-               return 0;\r
-\r
-       return gy[pointno];\r
-}\r
-\r
-bool TTF::GetOnCurve(uint16 pointno)\r
-{\r
-       if (pointno >= MAXPOINTS)\r
-               return true;\r
-\r
-       return onCurve[pointno];\r
-}\r
-\r
-bool TTF::SetOnCurve(uint16 pointno, bool state)\r
-{\r
-       if (pointno >= numberOfPoints)\r
-               return false;\r
-\r
-       onCurve[pointno] = state;\r
-       isDirty = true;\r
-\r
-       return true;\r
-}\r
-\r
-bool TTF::MovePoint(uint16 pointno, int x, int y)\r
-{\r
-       if (pointno >= numberOfPoints)\r
-               return false;\r
-\r
-       gx[pointno] = x;  gy[pointno] = y;\r
-       isDirty = true;\r
-\r
-       return true;\r
-}\r
-\r
-bool TTF::MovePoint(uint16 pointno, GlyphPt p)\r
-{\r
-       if (pointno >= numberOfPoints)\r
-               return false;\r
-\r
-       gx[pointno] = p.x;  gy[pointno] = p.y;  onCurve[pointno] = p.onCurve;\r
-       isDirty = true;\r
-\r
-       return true;\r
-}\r
-\r
-bool TTF::IsCompositeGlyph(void)\r
-{\r
-       return isCompositeGlyph;\r
-}\r
-\r
+//
+// TTF.CPP - The TrueType class
+// by James L. Hammons
+// (C) 2005 Underground Software
+//
+// This class encapsulates all the complexity of a TrueType Font File
+// database.  Included are functions to load, save, & initialize the
+// TTF database, move, add, & delete points & glyphs, i.e. manipulate
+// a TTF file in just about any way imaginable!
+//
+// JLH = James L. Hammons <jlhamm@acm.org>
+//
+// Who  When        What
+// ---  ----------  -----------------------------------------------------------
+// JLH  ??/??/199?  Created this file
+//
+//
+// STILL TO BE DONE:
+//
+// - Eliminate ALL references to BYTE, WORD, SBYTE, SWORD, etc.
+//
+
+#include <stdio.h>                                                             // For file handling, etc.
+#include <stdlib.h>
+#include <string.h>
+#include "charnames.h"
+#include "ttf.h"
+
+#define TTFDEBUG
+
+#ifdef TTFDEBUG
+#include "debug.h"
+#endif
+
+#define NUMTABS  24                   // Number of distinct tables
+
+
+/*void fskip(HANDLE file, uint32_t bytesToSkip)
+{
+       SetFilePointer(file, (LONG)bytesToSkip, NULL, FILE_CURRENT);
+}*/
+
+//
+// Get a BYTE from the current file...
+//
+uint8_t ReadByte(FILE * file)
+{
+       return (uint8_t)fgetc(file);
+}
+
+// The following routines get and put WORDs and DWORDs in little endian
+// format, so they should work no matter what endianess the platform that
+// holds the TTF object.
+
+//
+// Get a WORD from the current file...
+//
+uint16_t ReadWord(FILE * file)
+{
+       uint16_t word = (uint16_t)fgetc(file) << 8;
+       word |= (uint16_t)fgetc(file);
+
+       return word;
+}
+
+//
+// Get a double WORD from the current file...
+//
+uint32_t ReadDWord(FILE * file)
+{
+       uint32_t dword = 0;
+
+       for(int i=0; i<4; i++)
+       {
+               dword <<= 8;
+               dword |= (uint8_t)fgetc(file);
+       }
+
+       return dword;
+}
+
+//
+// Write a WORD to the current file...
+//
+void WriteWord(FILE * file, uint16_t word)
+{
+       fputc(word >> 8, file);                                         // Hi byte
+       fputc(word & 0xFF, file);                                       // Lo byte
+}
+
+//
+// Write a double WORD to the current file...
+//
+void WriteDWord(FILE * file, uint32_t dword)
+{
+       for(int i=0; i<4; i++)
+       {
+               fputc((char)(dword >> 24), file);
+               dword <<= 8;
+       }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Table extraction helper routines (inline 'em?)
+////////////////////////////////////////////////////////////////////////////
+
+//
+// Return a BYTE from a BYTE based table
+//
+uint8_t GetByte(uint8_t * table, uint32_t &ptr)
+{
+       return table[ptr++];
+}
+
+//
+// Return a WORD from a BYTE based table
+//
+uint16_t GetWord(uint8_t * table, uint32_t &ptr)
+{
+       uint16_t hi = table[ptr++];
+       uint16_t lo = table[ptr++];
+
+       return (uint16_t)((hi<<8) | lo);
+}
+
+//
+// Return a double WORD from a BYTE based table
+//
+uint32_t GetDWord(uint8_t * table, uint32_t &ptr)
+{
+       uint32_t hi1 = table[ptr++];
+       uint32_t lo1 = table[ptr++];
+       uint32_t hi2 = table[ptr++];
+       uint32_t lo2 = table[ptr++];
+
+       return (uint32_t)((hi1 << 24) | (lo1 << 16) | (hi2 << 8) | lo2);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Table storage helper routines (inline 'em?)
+////////////////////////////////////////////////////////////////////////////
+
+//
+// Store a BYTE in a BYTE based table
+//
+void SetByte(uint8_t * table, uint32_t &ptr, uint8_t data)
+{
+       table[ptr++] = data;
+}
+
+//
+// Store a WORD in a BYTE based table
+//
+void SetWord(uint8_t * table, uint32_t &ptr, uint16_t data)
+{
+       table[ptr++] = data>>8;  table[ptr++] = data&0xFF;
+}
+
+//
+// Store a DWORD in a BYTE based table
+//
+void SetDWord(uint8_t * table, uint32_t &ptr, uint32_t data)
+{
+       table[ptr++] = (uint8_t)(data >> 24); table[ptr++] = (uint8_t)(data >> 16);
+       table[ptr++] = (uint8_t)(data >> 8);  table[ptr++] = (uint8_t)(data & 0xFF);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Fixed point to float (& vice versa) conversions
+/////////////////////////////////////////////////////////////////////////////
+float FixedToFloat(int16_t fixed)
+{
+       return (float)fixed / 16384.0f;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// TTF Constructor
+/////////////////////////////////////////////////////////////////////////////
+TTF::TTF(void)
+{
+       loaded = false;                                                         // Set font initializer
+       isDirty = false;                                                        // Glyphs are clean
+       numberOfPolys = 0;                                                      // Set reasonable values
+       isCompositeGlyph = false;                                       // No composite glyph (yet)
+
+       parray[0] = &EBDT;  parray[1] = &EBLC;  parray[2] = &EBSC; // Init pointer
+       parray[3] = &LTSH;  parray[4] = &OS_2;  parray[5] = &PCLT; // array...
+       parray[6] = &VDMX;  parray[7] = &cmap;  parray[8] = &cvt; 
+       parray[9] = &fpgm;  parray[10] = &gasp; parray[11] = &glyf;
+       parray[12] = &hdmx; parray[13] = &head; parray[14] = &hhea;
+       parray[15] = &hmtx; parray[16] = &kern; parray[17] = &loca;
+       parray[18] = &maxp; parray[19] = &name; parray[20] = &post;
+       parray[21] = &prep; parray[22] = &vhea; parray[23] = &vmtx;
+
+       larray[0] = &EBDT_len;  larray[1] = &EBLC_len;  larray[2] = &EBSC_len;
+       larray[3] = &LTSH_len;  larray[4] = &OS_2_len;  larray[5] = &PCLT_len;
+       larray[6] = &VDMX_len;  larray[7] = &cmap_len;  larray[8] = &cvt_len;
+       larray[9] = &fpgm_len;  larray[10] = &gasp_len; larray[11] = &glyf_len;
+       larray[12] = &hdmx_len; larray[13] = &head_len; larray[14] = &hhea_len;
+       larray[15] = &hmtx_len; larray[16] = &kern_len; larray[17] = &loca_len;
+       larray[18] = &maxp_len; larray[19] = &name_len; larray[20] = &post_len;
+       larray[21] = &prep_len; larray[22] = &vhea_len; larray[23] = &vmtx_len;
+
+       for(uint32_t i=0; i<NUMTABS; i++)
+               *parray[i] = NULL;                                              // Init pointers...
+
+       for(uint32_t i=0; i<MAXGLYPHS; i++)
+               glyph[i] = NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// TTF Destructor
+/////////////////////////////////////////////////////////////////////////////
+TTF::~TTF()
+{
+       ClearTables();                                                          // This should handle deallocation correctly...
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Member function: void Init(void)
+//
+// This function initializes the TTF object, setting reasonable values for
+// the various internal variables used by the object.
+// [distinct from New?]
+/////////////////////////////////////////////////////////////////////////////
+void TTF::Init(void)
+{
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Clear the tables so that file can be reloaded
+/////////////////////////////////////////////////////////////////////////////
+void TTF::ClearTables(void)
+{
+       for(uint32_t i=0; i<NUMTABS; i++)
+       {
+               if ((*parray[i]) != NULL)
+               {
+                       free(*parray[i]);
+                       *parray[i] = NULL;
+                       *larray[i] = 0;
+               }
+       }  
+
+       for(uint32_t i=0; i<MAXGLYPHS; i++)
+       {
+               if (glyph[i] != NULL)
+               {
+                       free(glyph[i]);
+                       glyph[i] = NULL;
+               }
+       }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Member function: BOOL Load(const char * filename)
+//
+// This loads the TTF database from an external file.  Returns 'true' if
+// successful.
+/////////////////////////////////////////////////////////////////////////////
+bool TTF::Load(const char * filename)
+{
+//     unsigned char ch;                                                       // Temp variable
+//     UINT num_tabs;                                                          // Number of tables
+       uint32_t offset[NUMTABS], length[NUMTABS];      // Temporary storage...
+       char names[NUMTABS][5];
+       char narray[NUMTABS][5] = { "EBDT", "EBLC", "EBSC", "LTSH", "OS/2", "PCLT",
+               "VDMX", "cmap", "cvt ", "fpgm", "gasp", "glyf", "hdmx", "head", "hhea",
+               "hmtx", "kern", "loca", "maxp", "name", "post", "prep", "vhea", "vmtx" };
+
+       //loaded = false;
+//     file.open(filename, ios::binary|ios::in);       // Open the file
+       FILE * file = fopen(filename, "rb");
+
+       if (file == NULL)
+#ifdef TTFDEBUG
+{
+WriteLogMsg("Failed to open file!\n");
+#endif
+               return false;
+#ifdef TTFDEBUG
+}
+#endif
+
+       if (ReadDWord(file) != 0x00010000)
+#ifdef TTFDEBUG
+{
+WriteLogMsg("File was NOT a TTF file!\n");
+#endif
+               return false;                                                   // Not a TTF file...
+#ifdef TTFDEBUG
+}
+#endif
+
+       uint32_t num_tabs = ReadWord(file);                     // Get # of tables
+#ifdef TTFDEBUG
+WriteLogMsg("Number of tables is %u...\n", num_tabs);
+#endif
+//     fskip(file, 6);                                                         // Skip this shiat...
+       fseek(file, 6, SEEK_CUR);
+
+#ifdef TTFDEBUG
+WriteLogMsg("Reading names of tables...\n");
+#endif
+       for(uint32_t i=0; i<num_tabs; i++)
+       {
+//             ReadFile(file, names[i], 4, &bytesRead, NULL);
+               fread(names[i], 1, 4, file);
+               names[i][4] = 0;
+//             fskip(file, 4);                                                 // Checksum
+               fseek(file, 4, SEEK_CUR);                               // Checksum
+               offset[i] = ReadDWord(file);                    // Offset from start of file
+               length[i] = ReadDWord(file);                    // Length of table
+       }
+
+#ifdef TTFDEBUG
+WriteLogMsg("Reading tables...\n");
+#endif
+       for(uint32_t i=0; i<num_tabs; i++)
+       {
+               for(uint32_t j=0; j<NUMTABS; j++)
+               {
+                       if ((strcmp(names[i], narray[j])) == 0) // Found a match...
+                       {
+//                             *parray[j] = (uint8_t *)GlobalAlloc(GMEM_FIXED, length[i]);     // Allocate space
+                               *parray[j] = (uint8_t *)malloc(length[i]); // Alloc space
+
+                               if (*parray[j] == NULL)
+                                       return false;                           // Bail out if nothing allocated
+
+                               *larray[j] = length[i];                 // Set its length...
+//                             SetFilePointer(file, (LONG)offset[i], NULL, FILE_BEGIN);
+//                             ReadFile(file, *parray[j], length[i], &bytesRead, NULL);
+                               fseek(file, offset[i], SEEK_SET);
+                               fread(*parray[j], 1, length[i], file);
+                               break;
+                       }
+               }
+       }
+
+       fclose(file);
+
+// This shouldn't be necessary, since it's irrelevant (loaded flag)
+//    loaded = true;                       // Set 'loaded' flag...
+    isDirty = false;                     // Glyphs are clean
+    ExtractTables();                     // Move table data to my structs
+                                         // & ignore return val
+                                         // (should handle errors here)
+       return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Member function: BOOL Save(const char * filename)
+//
+// Save the TT font currently in the object
+/////////////////////////////////////////////////////////////////////////////
+bool TTF::Save(const char * filename)
+{
+//  fstream file;
+//     ULONG offset = 12;
+       uint32_t numtabs = 0;
+       char padding[3] = { 0, 0, 0 };
+       // Convert this to a table of ULONGs to decrease complexity...
+//wouldn't be endian safe then...
+       char narray[NUMTABS][5] = { "EBDT", "EBLC", "EBSC", "LTSH", "OS/2", "PCLT",
+               "VDMX", "cmap", "cvt ", "fpgm", "gasp", "glyf", "hdmx", "head", "hhea",
+               "hmtx", "kern", "loca", "maxp", "name", "post", "prep", "vhea", "vmtx" };
+
+       if (isDirty)
+               EncodeGlyph(currentGlyph);
+
+       BuildTables();                                                          // Ignore return value...  
+
+       for(uint32_t i=0; i<NUMTABS; i++)                               // Figure out how many tables there are
+               if ((*parray[i]) != NULL)
+                       numtabs++;
+
+       uint32_t offset = 12 + (numtabs * 16);          // Calc correct offset to start of data
+
+//     HANDLE file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+//             NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+       FILE * file = fopen(filename, "wb");
+
+       WriteDWord(file, 0x00010000);                           // Write header...
+       WriteWord(file, numtabs);
+       WriteWord(file, 0);                                                     // SearchRange (Max power of 2 <= numTables) x 16.
+       WriteWord(file, 0);                                                     // entrySelector Log2(max power of 2 <= numTables).
+       WriteWord(file, 0);                                                     // NumTables x 16 - searchRange.
+
+       for(uint32_t i=0; i<NUMTABS; i++)                                       // Write out table directory...
+       {
+               if ((*parray[i]) != NULL)
+               {
+//                     for(int j=0; j<4; j++)
+//                             file.put(narray[i][j]);                 // Name
+//                     WriteFile(file, narray[i], 4, &bytesWritten, NULL);
+                       fwrite(narray[i], 1, 4, file);          // Name
+
+                       WriteDWord(file, 0);                            // Checksum
+                       WriteDWord(file, offset);                       // Offset
+                       WriteDWord(file, (*larray[i]));         // Length
+
+                       offset += (((*larray[i]) + 3) & ~3);    // Pad out to 4-uint8_t boundary...
+               }
+       }
+
+       for(uint32_t i=0; i<NUMTABS; i++)                                       // Write out the tables...
+       {
+               if ((*parray[i]) != NULL)
+               {
+//                     for(uint32_t j=0; j<(*larray[i]); j++)
+//                             file.put((*parray[i])[j]);
+//                     WriteFile(file, *parray[i], *larray[i], &bytesWritten, NULL);
+                       fwrite(*parray[i], 1, *larray[i], file);
+
+                       uint32_t remainder = ((*larray[i]) & 0x3);
+                       if (remainder)               // i.e., it's not evenly div by 4
+//                             for(j=remainder; j<4; j++)
+//                                     file.put((char)0);       // pad it!
+//                             WriteFile(file, padding, 4 - remainder, &bytesWritten, NULL);
+                               fwrite(padding, 1, 4 - remainder, file);
+               }
+       }
+
+       fclose(file);
+
+       return true;                                                            // Whether or not it was successful...
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Member function: BOOL EncodeGlyph(int glyphnum)
+//
+// This function encodes the glyph data and stores it to the 'glyf' table.
+/////////////////////////////////////////////////////////////////////////////
+bool TTF::EncodeGlyph(uint16_t glyphnum)
+{
+       bool retval = false;                                            // Assume failure
+       uint8_t flag, xbuf[4000], ybuf[4000], fbuf[2000];
+       uint32_t xp = 0, yp = 0, fp = 0;                                // Table pointers
+
+       if (glyphnum < myMaxp.numGlyphs)  // numofgls is 1 based ind, glyph# 0 based
+       {
+               // need to add composite encoding...
+               int lastx = 0, lasty = 0;
+
+               for(uint32_t i=0; i<numberOfPoints; i++)
+               {
+                       flag = 0;
+                       int curx = gx[i] - lastx, cury = gy[i] - lasty;
+
+                       if (onCurve[i])
+                               flag |= 0x01;                                   // Set on curve info
+
+                       if (curx)
+                       {
+                               if ((curx > 255) || (curx < -255)) // I.e., it's 2 uint8_t value
+                                       SetWord(xbuf, xp, curx);
+                               else
+                               {
+                                       if (curx & 0x100)
+                                       {
+                                               flag |= 0x02; // I.e., it's negative
+                                               curx *= -1;   // Flip it so correct value is stored
+                                       }
+                                       else
+                                               flag |= 0x12;
+
+                                       SetByte(xbuf, xp, curx);        // Automagically strips neg bit
+                               }
+                       }
+                       else
+                               flag |= 0x10;                                   // X-coord is same...
+  
+                       if (cury)
+                       {
+                               if ((cury > 255) || (cury < -255)) // I.e., it's 2 uint8_t value
+                                       SetWord(ybuf, yp, cury);
+                               else
+                               {
+                                       if (cury & 0x100)
+                                       {
+                                               flag |= 0x04; // I.e., it's negative
+                                               cury *= -1;
+                                       }
+                                       else
+                                               flag |= 0x24;
+            
+                                       SetByte(ybuf, yp, cury);
+                               }
+                       }
+                       else
+                               flag |= 0x20;                 // Y-coord is same...
+  
+                       fbuf[i] = flag;
+                       lastx = gx[i];  lasty = gy[i];
+               }
+
+               // Now crunch flags...  ugly, ugly, ugly.
+/*
+    fbuf[numberOfPoints] = 0;  // Set sentinel value (ugly way to do this)
+    for(i=0; i<numberOfPoints; i++);
+    {
+      if (fbuf[i] == fbuf[i+1])  // 
+      {
+        uint8_t count = 0;  // Sentinel takes care of check for end of flags...
+        while (fbuf[i] == fbuf[++i])  count++; // Count number of repeats
+        i--;
+        fbuf[fp++] = fbuf[i] | 0x08; // Set repeat flag
+        fbuf[fp++] = count;          // & number of repeats
+      }
+      else  fbuf[fp++] = fbuf[i];    // Otherwise, just copy...
+    }
+*/
+               fp = numberOfPoints;
+               // Find length of glyph and reallocate space if necessary
+
+               uint32_t newLength = 12 + numberOfPolys*2 + numberOfHints + fp + xp + yp;
+
+               if (newLength & 0x03)
+                       newLength += (4 - newLength & 0x03);
+
+               if (glyphLen[glyphnum] != newLength)
+               {
+                       glyph[glyphnum] = (uint8_t *)realloc(glyph[glyphnum], newLength);
+                       glyphLen[glyphnum] = newLength;
+               }
+
+               // And finally, store it!
+
+               uint32_t gp = 0;                                                        // Glyph pointer...
+               SetWord(glyph[glyphnum], gp, numberOfPolys);
+               SetWord(glyph[glyphnum], gp, llx);
+               SetWord(glyph[glyphnum], gp, lly);
+               SetWord(glyph[glyphnum], gp, urx);
+               SetWord(glyph[glyphnum], gp, ury);
+               for(uint32_t i=0; i<numberOfPolys; i++)
+                       SetWord(glyph[glyphnum], gp, poly[i]);
+               SetWord(glyph[glyphnum], gp, numberOfHints);
+               for(uint32_t i=0; i<numberOfHints; i++)
+                       SetByte(glyph[glyphnum], gp, hint[i]);
+               for(uint32_t i=0; i<fp; i++)
+                       SetByte(glyph[glyphnum], gp, fbuf[i]);
+               for(uint32_t i=0; i<xp; i++)
+                       SetByte(glyph[glyphnum], gp, xbuf[i]);
+               for(uint32_t i=0; i<yp; i++)
+                       SetByte(glyph[glyphnum], gp, ybuf[i]);
+
+               retval = true;                                                  // Successfully encoded!
+       }
+
+       return retval;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Member function: BOOL DecodeGlyph(int glyphnum)
+//
+// This function decodes the glyph data and stores it to the object's
+// internal array.
+/////////////////////////////////////////////////////////////////////////////
+bool TTF::DecodeGlyph(uint16_t glyphnum)
+{
+       bool retval = false;
+       uint32_t i, dp;
+
+       // glyphnum is 0 based index, while numGlyphs is 1 based
+       if (glyphnum >= myMaxp.numGlyphs)
+               return false;  // Invalid char #
+
+       if (!glyphLen[glyphnum])
+       {
+               numberOfPoints = numberOfPolys = 0;
+               return true;                                                    // Zero length IS valid...
+       }
+//     else                                                                            // Get character data...
+//     {
+    // Now get the character data...
+       dp = 0;                     // Reset data pointer
+       isCompositeGlyph = false;   // Default is no
+       numberOfPolys = GetWord(glyph[glyphnum], dp);  // # of polygons
+
+       llx = (int16_t)GetWord(glyph[glyphnum], dp);           // Lower left X
+       lly = (int16_t)GetWord(glyph[glyphnum], dp);           // Lower left Y
+       urx = (int16_t)GetWord(glyph[glyphnum], dp);           // Upper right X
+       ury = (int16_t)GetWord(glyph[glyphnum], dp);           // Upper right Y
+
+       // Need to handle composite glyphs better here.  The ways things
+       // are set now is a recipe for disaster...
+
+       if (numberOfPolys == 0xFFFF)
+       {
+               isCompositeGlyph = true;
+               numberOfPolys = 0;                                              // Set for no points
+
+               Composite cmpst;
+
+               while (!compositeList.IsEmpty())                // Empty composite list...
+                       compositeList.GetFront();
+
+               do
+               {
+                       cmpst.flags = GetWord(glyph[glyphnum], dp);
+                       cmpst.glyphIndex = GetWord(glyph[glyphnum], dp);
+                       cmpst.arg1 = (cmpst.flags & 0x01 ? (int16_t)GetWord(glyph[glyphnum], dp) : (int8_t)GetByte(glyph[glyphnum], dp));
+                       cmpst.arg2 = (cmpst.flags & 0x01 ? (int16_t)GetWord(glyph[glyphnum], dp) : (int8_t)GetByte(glyph[glyphnum], dp));
+
+                       if (cmpst.flags & 0x08)
+                               cmpst.xScale = cmpst.yScale = FixedToFloat((int16_t)GetWord(glyph[glyphnum], dp));
+                       else if (cmpst.flags & 0x40)
+                               cmpst.xScale = FixedToFloat((int16_t)GetWord(glyph[glyphnum], dp)),
+                               cmpst.yScale = FixedToFloat((int16_t)GetWord(glyph[glyphnum], dp));
+                       else if (cmpst.flags & 0x80)
+                               cmpst.xScale = FixedToFloat((int16_t)GetWord(glyph[glyphnum], dp)),
+                               cmpst.scale01 = FixedToFloat((int16_t)GetWord(glyph[glyphnum], dp)),
+                               cmpst.scale10 = FixedToFloat((int16_t)GetWord(glyph[glyphnum], dp)),
+                               cmpst.yScale = FixedToFloat((int16_t)GetWord(glyph[glyphnum], dp));
+
+                       compositeList.AddAtRear(cmpst);
+               }
+               while (cmpst.flags & 0x20); //*/
+
+               return true;
+       }
+
+//do {
+//     USHORT flags;
+//     USHORT glyphIndex;
+//     if ( flags & ARG_1_AND_2_ARE_uint16_tS) {
+//     (SHORT or Fuint16_t) argument1;
+//     (SHORT or Fuint16_t) argument2;
+//     } else {
+//             USHORT arg1and2; /* (arg1 << 8) | arg2 */
+//     }
+//     if ( flags & WE_HAVE_A_SCALE ) {
+//             F2Dot14  scale;    /* Format 2.14 */
+//     } else if ( flags & WE_HAVE_AN_X_AND_Y_SCALE ) {
+//             F2Dot14  xscale;    /* Format 2.14 */
+//             F2Dot14  yscale;    /* Format 2.14 */
+//     } else if ( flags & WE_HAVE_A_TWO_BY_TWO ) {
+//             F2Dot14  xscale;    /* Format 2.14 */
+//             F2Dot14  scale01;   /* Format 2.14 */
+//             F2Dot14  scale10;   /* Format 2.14 */
+//             F2Dot14  yscale;    /* Format 2.14 */
+//     }
+//} while ( flags & MORE_COMPONENTS ) 
+//if (flags & WE_HAVE_INSTR){
+//     USHORT numInstr
+//     uint8_t instr[numInstr]
+//
+//Flags                    Bit     Description 
+//ARG_1_AND_2_ARE_uint16_tS    0       If this is set, the arguments are uint16_ts;
+//                                 otherwise, they are uint8_ts.
+//ARGS_ARE_XY_VALUES       1       If this is set, the arguments are xy values;
+//                                 otherwise, they are points.
+//ROUND_XY_TO_GRID         2       For the xy values if the preceding is true.
+//WE_HAVE_A_SCALE          3       This indicates that there is a simple scale
+//                                 for the component. Otherwise, scale = 1.0.
+//RESERVED                 4       This bit is reserved.  Set it to 0. 
+//MORE_COMPONENTS          5       Indicates at least one more glyph after this
+//                                 one.
+//WE_HAVE_AN_X_AND_Y_SCALE 6       The x direction will use a different scale
+//                                 from the y direction.
+//WE_HAVE_A_TWO_BY_TWO     7       There is a 2 by 2 transformation that will
+//                                 be used to scale the component.
+//WE_HAVE_INSTRUCTIONS     8       Following the last component are
+//                                 instructions for the composite character.
+//USE_MY_METRICS           9       If set, this forces the aw and lsb (and rsb)
+//                                 for the composite to be equal to those from
+//                                 this original glyph. This works for hinted
+//                                 and unhinted characters.
+
+       for(i=0; i<numberOfPolys; i++)
+               poly[i] = GetWord(glyph[glyphnum], dp);
+
+       numberOfHints = GetWord(glyph[glyphnum], dp);
+
+       for(i=0; i<numberOfHints; i++)
+               hint[i] = GetByte(glyph[glyphnum], dp);
+
+       // Decode the dots...
+
+       uint32_t num_pts = poly[numberOfPolys-1] + 1;
+       numberOfPoints = num_pts; // necessary??
+       uint32_t xptr, yptr;        // pointers to beginning of coord data
+       uint32_t numXs = 0;
+       int xx = 0, yy = 0, repeat;
+       uint32_t numTokens = num_pts, k, numRep;
+
+       // We make an educated guess that num_pts = num_tokens; but if there
+       // is repeated data in the tokens, then we need to adjust the # of
+       // tokens down appropriately.
+
+       for(uint32_t i=0; i<numTokens; i++)
+       {
+               uint8_t token = glyph[glyphnum][dp+i];  uint32_t rpts = 1;
+
+               if (token & 0x08)      // Repeated token?
+               {
+                       i++;                 // Yes, bump pointer to # of times to repeat
+                       numRep = glyph[glyphnum][dp+i];
+                       rpts += numRep;
+
+                       if (numRep > 1)      // Do we need to adjust numTokens?
+   // this is bad, modifying numTokens while it's used as a compare value
+   // in the above loop...
+   // Is it necessary to do so in order to keep from going too far?
+                       numTokens -= (numRep - 1); // Yes, adjust.
+               }
+
+               // 10 = same x(0uint8_ts), 00 = 2uint8_ts, 02&12 = 1uint8_t
+               if ((token & 0x02) == 0x02)
+                       numXs += rpts;
+
+               if ((token & 0x12) == 0x00)
+                       numXs += (rpts*2);
+       }
+
+       xptr = dp + numTokens;
+       yptr = dp + numTokens + numXs;
+
+       // & continue decoding X/Y-coords...
+
+       k = 0;                               // Index to the point array
+
+       for(uint32_t i=0; i<numTokens; i++)
+       {
+               uint8_t token = glyph[glyphnum][dp+i];
+               repeat = 1;
+
+               if (token & 0x08)
+               {
+                       i++;
+                       repeat += glyph[glyphnum][dp+i]; // Set repeat data...
+               }
+
+               while (repeat--)
+               {
+                       if ((token & 0x12) == 0x12)
+                               xx += GetByte(glyph[glyphnum], xptr);
+
+                       if ((token & 0x12) == 0x02)
+                               xx -= GetByte(glyph[glyphnum], xptr);
+
+                       if ((token & 0x12) == 0x00)
+                               xx += (int16_t)GetWord(glyph[glyphnum], xptr);
+
+                       gx[k] = xx;                      // Store x-coordinate
+
+                       if ((token & 0x24) == 0x24)
+                               yy += GetByte(glyph[glyphnum], yptr);
+
+                       if ((token & 0x24) == 0x04)
+                               yy -= GetByte(glyph[glyphnum], yptr);
+
+                       if ((token & 0x24) == 0x00)
+                               yy += (int16_t)GetWord(glyph[glyphnum], yptr);
+
+                       gy[k] = yy;                      // Store y-coordinate
+
+                       onCurve[k++] = (token & 0x01 ? true : false);  // If bit 0 set, then it's on curve
+               }
+       }
+
+       retval = true;                                                  // Hmm. Successfully decoded a glyph...
+//     }
+
+       isDirty = false;  // do it here?
+
+       return retval;
+}
+
+/*****************************************************************************
+ Member function:
+
+ This function decodes the 'glyf' data for a non-composite (atomic) glyph and
+ returns it as a GlyphPoints object. Helper function.
+ *****************************************************************************/
+GlyphPoints TTF::GetGlyphPoints(uint16_t glyphNum)
+{
+       if (DecodeGlyph(glyphNum))
+               return GlyphPoints(numberOfPoints, numberOfPolys, gx, gy, onCurve, poly);
+
+       return GlyphPoints();
+}
+
+/*****************************************************************************
+ Member function:
+
+ This function decodes the 'glyf' data for a composite glyph and returns
+ it as a GlyphPoints object.
+ *****************************************************************************/
+GlyphPoints TTF::GetAllCompositePoints(uint16_t glyphNum)
+{
+//  int tmpGlyph = currentGlyph;
+  
+       DecodeGlyph(glyphNum);         // Check for composite-ness
+
+       if (!isCompositeGlyph)
+               return GlyphPoints();
+
+/*
+  for(int i=1; i<=pDoc->m_myFont.compositeList.Length(); i++)
+  {
+    TComposite cmpst = fnt->compositeList.PeekPosition(i);
+    fnt->SetGlyph(cmpst.glyphIndex);
+    if (cmpst.flags & 0x0002)
+      m_nXOffset = cmpst.arg1, m_nYOffset = cmpst.arg2;
+    ScanConvertSingleGlyph(pDC, nScanlines, nHorzLines, nXOffset, nYOffset);
+  }
+  fnt->SetGlyph(pDoc->character_num);
+*/
+
+       GlyphPoints retVal;
+
+       for(int i=1; i<=compositeList.Length(); i++)
+       {
+               Composite cmpst = compositeList.PeekPosition(i);
+    
+//    SetGlyph(cmpst.glyphIndex);
+//    if (cmpst.flags & 0x0002)
+//      m_nXOffset = cmpst.arg1, m_nYOffset = cmpst.arg2;
+//    ScanConvertSingleGlyph(pDC, nScanlines, nHorzLines, nXOffset, nYOffset);
+               GlyphPoints gp = GetGlyphPoints(cmpst.glyphIndex);
+
+               if (cmpst.flags & 0x0002)
+                       gp.OffsetPoints(cmpst.arg1, cmpst.arg2);
+
+               retVal = retVal + gp;
+               // NOTE: May have to adjust scanlines as per 0x0002 above...
+       }
+
+//  SetGlyph(tmpGlyph);
+       DecodeGlyph(currentGlyph);     // Reset needed here...
+
+       return retVal;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Member function: void GetCharName(int cNum, uint8_t * buf)
+//
+// This function returns the character name of the glyph number passed in.
+/////////////////////////////////////////////////////////////////////////////
+void TTF::GetCharName(int cNum, uint8_t * buf)
+{
+       buf[0] = 0;                                                                     // Set failure as default condition
+  
+       if (!post)                                                                      // PS names are here...
+               return;
+
+       if (post[1] != 0x02 || post[2] != 0x00)         // i.e., it's NOT a V2.0 table
+               return;
+
+       uint8_t * pTab = NULL;
+       uint32_t tabOff = 34, numGlyphs = (uint32_t)((post[32] << 8) | post[33]);
+       uint32_t index = (uint32_t)((post[tabOff + cNum * 2] << 8) | post[tabOff + cNum * 2 + 1]);
+       uint32_t nInd2;
+
+       if (index > 257)
+       {
+               index -= 258;
+               nInd2 = tabOff + (2 * numGlyphs);
+               pTab = post;
+       }
+       else
+       {
+               nInd2 = 0;
+               pTab = macStdNames;
+       }
+
+       for(uint32_t i=0; i<index; i++)
+               nInd2 = nInd2 + pTab[nInd2] + 1; // 1st uint8_t is length of string + that uint8_t
+
+       uint8_t len = pTab[nInd2];
+       nInd2++;
+
+       for(uint8_t i=0; i<len; i++)
+               buf[i] = pTab[nInd2 + i];
+
+       buf[len] = 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Member function: BOOL ExtractTables(void)
+//
+// This function extracts the data from the various tables and puts them in
+// various structs for easier handling of the font data.
+/////////////////////////////////////////////////////////////////////////////
+bool TTF::ExtractTables(void)
+{
+       if (head_len != 54)
+       {
+#ifdef TTFDEBUG
+WriteLogMsg("Bad HEAD header: Expected 54, found %u...\n", head_len);
+#endif
+               return false;                                                   // Corrupt data?
+       }
+
+       uint32_t tp = 0;
+       myHead.version            = GetDWord(head, tp);
+       myHead.fontRevision       = GetDWord(head, tp);
+       myHead.checkSumAdjustment = GetDWord(head, tp);
+       myHead.magicNumber        = GetDWord(head, tp);
+       myHead.flags              = GetWord(head, tp);
+       myHead.unitsPerEm         = GetWord(head, tp);
+       myHead.createdh           = GetDWord(head, tp);
+       myHead.createdl           = GetDWord(head, tp);
+       myHead.modifiedh          = GetDWord(head, tp);
+       myHead.modifiedl          = GetDWord(head, tp);
+       myHead.xMin               = GetWord(head, tp);
+       myHead.yMin               = GetWord(head, tp);
+       myHead.xMax               = GetWord(head, tp);
+       myHead.yMax               = GetWord(head, tp);
+       myHead.macStyle           = GetWord(head, tp);
+       myHead.lowestRecPPEM      = GetWord(head, tp);
+       myHead.fontDirectionHint  = (int16_t)GetWord(head, tp);
+       myHead.indexToLocFormat   = (int16_t)GetWord(head, tp);
+       myHead.glyphDataFormat    = (int16_t)GetWord(head, tp);
+
+       if (maxp_len != 32)
+       {
+#ifdef TDEBUG
+WriteLogMsg("Bad MAXP header: Expected 32, found %u...\n", maxp_len);
+#endif
+               return false;                                                   // Corrupt data?
+       }
+
+       tp = 0;                                                                         // Reset table pointer
+       myMaxp.version               = GetDWord(maxp, tp);
+       myMaxp.numGlyphs             = GetWord(maxp, tp);
+       myMaxp.maxPoints             = GetWord(maxp, tp);
+       myMaxp.maxContours           = GetWord(maxp, tp);
+       myMaxp.maxCompositePoints    = GetWord(maxp, tp);
+       myMaxp.maxCompositeContours  = GetWord(maxp, tp);
+       myMaxp.maxZones              = GetWord(maxp, tp);
+       myMaxp.maxTwilightPoints     = GetWord(maxp, tp);
+       myMaxp.maxStorage            = GetWord(maxp, tp);
+       myMaxp.maxFunctionDefs       = GetWord(maxp, tp);
+       myMaxp.maxInstructionDefs    = GetWord(maxp, tp);
+       myMaxp.maxStackElements      = GetWord(maxp, tp);
+       myMaxp.maxSizeOfInstructions = GetWord(maxp, tp);
+       myMaxp.maxComponentElements  = GetWord(maxp, tp);
+       myMaxp.maxComponentDepth     = GetWord(maxp, tp);
+
+       tp = 0;                                                                         // Reset table pointer
+       uint32_t start = (myHead.indexToLocFormat ? GetDWord(loca, tp) : GetWord(loca, tp) << 1);
+
+       for(uint32_t i=0; i<myMaxp.numGlyphs; i++)
+       {
+               uint32_t end = (myHead.indexToLocFormat ? GetDWord(loca, tp) : GetWord(loca, tp) << 1);
+               uint32_t length = end - start;
+               glyphLen[i] = length;                                   // Lengths are saved 'cause malloc is sloppy
+
+               if (length)     // loca+start? pointer arithmetic?
+               {
+                       glyph[i] = (uint8_t *)malloc(length);   // Allocate space,
+                       memcpy(glyph[i], glyf+start, length);   // and move it!
+               }
+               else
+                       glyph[i] = NULL;
+
+               start = end;                                                    // Reset start value
+       }
+
+       return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Member function: BOOL BuildTables(void)
+//
+// This function builds the various TTF tables using info in the various
+// structs so that a TTF file can be written out to disk.
+/////////////////////////////////////////////////////////////////////////////
+bool TTF::BuildTables(void)
+{
+       uint32_t i, tp, start;
+
+       myHead.indexToLocFormat = 1;                            // We don't bother with [uint16_ts*2] format...
+
+       // Build HEAD table
+
+       tp = 0;                                                                         // Reset table pointer
+       SetDWord(head, tp, myHead.version);//            = GetDWord(head, tp);
+       SetDWord(head, tp, myHead.fontRevision);//       = GetDWord(head, tp);
+       SetDWord(head, tp, myHead.checkSumAdjustment);// = GetDWord(head, tp);
+       SetDWord(head, tp, myHead.magicNumber);//        = GetDWord(head, tp);
+       SetWord(head, tp, myHead.flags);//              = GetWord(head, tp);
+       SetWord(head, tp, myHead.unitsPerEm);//         = GetWord(head, tp);
+       SetDWord(head, tp, myHead.createdh);//           = GetDWord(head, tp);
+       SetDWord(head, tp, myHead.createdl);//           = GetDWord(head, tp);
+       SetDWord(head, tp, myHead.modifiedh);//          = GetDWord(head, tp);
+       SetDWord(head, tp, myHead.modifiedl);//          = GetDWord(head, tp);
+       SetWord(head, tp, myHead.xMin);//               = GetWord(head, tp);
+       SetWord(head, tp, myHead.yMin);//               = GetWord(head, tp);
+       SetWord(head, tp, myHead.xMax);//               = GetWord(head, tp);
+       SetWord(head, tp, myHead.yMax);//               = GetWord(head, tp);
+       SetWord(head, tp, myHead.macStyle);//           = GetWord(head, tp);
+       SetWord(head, tp, myHead.lowestRecPPEM);//      = GetWord(head, tp);
+       SetWord(head, tp, myHead.fontDirectionHint);//  = (int16_t)GetWord(head, tp);
+       SetWord(head, tp, myHead.indexToLocFormat);//   = (int16_t)GetWord(head, tp);
+       SetWord(head, tp, myHead.glyphDataFormat);//    = (int16_t)GetWord(head, tp);
+
+       // Build MAXP table
+
+       tp = 0;                                                                         // Reset table pointer
+       SetDWord(maxp, tp, myMaxp.version);//               = GetDWord(maxp, tp);
+       SetWord(maxp, tp, myMaxp.numGlyphs);//             = GetWord(maxp, tp);
+       SetWord(maxp, tp, myMaxp.maxPoints);//             = GetWord(maxp, tp);
+       SetWord(maxp, tp, myMaxp.maxContours);//           = GetWord(maxp, tp);
+       SetWord(maxp, tp, myMaxp.maxCompositePoints);//    = GetWord(maxp, tp);
+       SetWord(maxp, tp, myMaxp.maxCompositeContours);//  = GetWord(maxp, tp);
+       SetWord(maxp, tp, myMaxp.maxZones);//              = GetWord(maxp, tp);
+       SetWord(maxp, tp, myMaxp.maxTwilightPoints);//     = GetWord(maxp, tp);
+       SetWord(maxp, tp, myMaxp.maxStorage);//            = GetWord(maxp, tp);
+       SetWord(maxp, tp, myMaxp.maxFunctionDefs);//       = GetWord(maxp, tp);
+       SetWord(maxp, tp, myMaxp.maxInstructionDefs);//    = GetWord(maxp, tp);
+       SetWord(maxp, tp, myMaxp.maxStackElements);//      = GetWord(maxp, tp);
+       SetWord(maxp, tp, myMaxp.maxSizeOfInstructions);// = GetWord(maxp, tp);
+       SetWord(maxp, tp, myMaxp.maxComponentElements);//  = GetWord(maxp, tp);
+       SetWord(maxp, tp, myMaxp.maxComponentDepth);//     = GetWord(maxp, tp);
+
+       // Build LOCA & GLYF tables
+
+       loca_len = (myMaxp.numGlyphs+1) * 4;            // Set size of table
+
+       if (loca)
+               free(loca);                                                             // And create/reallocate it...
+
+       loca = (uint8_t *) malloc(loca_len);
+
+       glyf_len = 0;                                                           // Refigure glyf table length
+
+       for(i=0; i<myMaxp.numGlyphs; i++)
+               glyf_len += glyphLen[i];
+
+       if (glyf)
+               free(glyf);
+
+       glyf = (uint8_t *) malloc(glyf_len);
+
+       start = tp = 0;                                                         // Reset table pointer
+
+       for(i=0; i<myMaxp.numGlyphs; i++)
+       {
+               SetDWord(loca, tp, start);                              // Store glyph start address
+
+               if (glyphLen[i])
+                       memcpy(glyf+start, glyph[i], glyphLen[i]);
+
+               start += glyphLen[i];
+       }
+
+       SetDWord(loca, tp, start);                                      // Finally, store end of glyphs+1
+
+       return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Member function: BOOL SetGlyph(int glyphnum)
+//
+// This function decodes the glyph data and stores the points in its own
+// internal array.  If the flag isDirty is set, it also encodes the internal
+// array and stores it to the 'glyf' table.
+/////////////////////////////////////////////////////////////////////////////
+bool TTF::SetGlyph(uint16_t glyphnum)
+{
+       bool retval = false;                                            // Set failure as default
+
+       if (isDirty)
+               EncodeGlyph(currentGlyph);
+
+       isDirty = false;
+
+       if (glyphnum < myMaxp.numGlyphs)                        // numofgls is 1 based ind, glyph# 0 based
+       {
+               currentGlyph = glyphnum;
+               DecodeGlyph(currentGlyph);
+               retval = true;
+       }
+
+       return retval;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Member function: BOOL AddGlyph(int glyphnum)
+//
+// This function adds a glyph of zero size at position glyphnum.  If glyphnum
+// is greater than the number of glyphs, glyph is added at end of list. This
+// glyph then becomes the current glyph.
+/////////////////////////////////////////////////////////////////////////////
+bool TTF::AddGlyph(uint16_t glyphnum)
+{
+       // incomplete: JLH
+       bool retval = false;
+
+       if (isDirty)
+               EncodeGlyph(currentGlyph);
+
+       isDirty = false;
+
+       return retval;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Member function: BOOL DeleteGlyph(int glyphnum)
+//
+// This function deletes the glyph at position glyphnum.  All glyphs after
+// this glyph are moved down in position.
+/////////////////////////////////////////////////////////////////////////////
+bool TTF::DeleteGlyph(uint16_t glyphnum)
+{
+       // incomplete: JLH
+       bool retval = false;
+
+       return retval;
+}
+
+//
+// Various & sundry member functions implementation
+//
+// NOTE: For error handling, should throw exceptions--not return values...! !!! FIX !!!
+//
+
+Box TTF::GetBoundingBox(void)
+{
+       return Box(llx, lly, urx, ury);
+}
+
+GlyphPt TTF::GetPoint(uint16_t pointno)
+{
+       GlyphPt p;
+
+       if (pointno >= MAXPOINTS)
+               return p; // Fix to make invalid
+
+       p.x = gx[pointno], p.y = gy[pointno], p.onCurve = onCurve[pointno];
+       return p;
+}
+
+uint16_t TTF::GetNumberOfPolys(void)
+{
+       return numberOfPolys;
+}
+
+uint16_t TTF::GetPolyEnd(uint16_t polynum)
+{
+       if (polynum >= numberOfPolys)
+               return 0;
+
+       return poly[polynum];
+}
+
+int TTF::GetPointX(uint16_t pointno)
+{
+       if (pointno >= MAXPOINTS)
+               return 0;
+
+       return gx[pointno];
+}
+
+int TTF::GetPointY(uint16_t pointno)
+{
+       if (pointno >= MAXPOINTS)
+               return 0;
+
+       return gy[pointno];
+}
+
+bool TTF::GetOnCurve(uint16_t pointno)
+{
+       if (pointno >= MAXPOINTS)
+               return true;
+
+       return onCurve[pointno];
+}
+
+bool TTF::SetOnCurve(uint16_t pointno, bool state)
+{
+       if (pointno >= numberOfPoints)
+               return false;
+
+       onCurve[pointno] = state;
+       isDirty = true;
+
+       return true;
+}
+
+bool TTF::MovePoint(uint16_t pointno, int x, int y)
+{
+       if (pointno >= numberOfPoints)
+               return false;
+
+       gx[pointno] = x;  gy[pointno] = y;
+       isDirty = true;
+
+       return true;
+}
+
+bool TTF::MovePoint(uint16_t pointno, GlyphPt p)
+{
+       if (pointno >= numberOfPoints)
+               return false;
+
+       gx[pointno] = p.x;  gy[pointno] = p.y;  onCurve[pointno] = p.onCurve;
+       isDirty = true;
+
+       return true;
+}
+
+bool TTF::IsCompositeGlyph(void)
+{
+       return isCompositeGlyph;
+}
+