]> Shamusworld >> Repos - ttedit/blob - src/ttf.cpp
ce312a8d6dfc2ddd70265dfc0f9265f4a13028ae
[ttedit] / src / ttf.cpp
1 //
2 // TTF.CPP - The TrueType class
3 // by James L. Hammons
4 // (C) 2005 Underground Software
5 //
6 // This class encapsulates all the complexity of a TrueType Font File
7 // database.  Included are functions to load, save, & initialize the
8 // TTF database, move, add, & delete points & glyphs, i.e. manipulate
9 // a TTF file in just about any way imaginable!
10 //
11 // JLH = James L. Hammons <jlhamm@acm.org>
12 //
13 // Who  When        What
14 // ---  ----------  -------------------------------------------------------------
15 // JLH  ??/??/199?  Created this file
16 //
17 //
18 // STILL TO BE DONE:
19 //
20 // - Eliminate ALL references to BYTE, WORD, SBYTE, SWORD, etc.
21 //
22
23 #include <stdio.h>                                                              // For file handling, etc.                                                                                              //
24 #include <stdlib.h>
25 #include <string.h>
26 #include "charnames.h"
27 #include "ttf.h"
28
29 #define TTFDEBUG
30
31 #ifdef TTFDEBUG
32 #include "debug.h"
33 #endif
34
35 #define NUMTABS  24                   // Number of distinct tables
36
37
38 /*void fskip(HANDLE file, uint32 bytesToSkip)
39 {
40         SetFilePointer(file, (LONG)bytesToSkip, NULL, FILE_CURRENT);
41 }*/
42
43 //
44 // Get a BYTE from the current file...
45 //
46 uint8 ReadByte(FILE * file)
47 {
48         return (uint8)fgetc(file);
49 }
50
51 // The following routines get and put WORDs and DWORDs in little endian
52 // format, so they should work no matter what endianess the platform that
53 // holds the TTF object.
54
55 //
56 // Get a WORD from the current file...
57 //
58 uint16 ReadWord(FILE * file)
59 {
60         uint16 word = (uint16)fgetc(file) << 8;
61         word |= (uint16)fgetc(file);
62
63         return word;
64 }
65
66 //
67 // Get a double WORD from the current file...
68 //
69 uint32 ReadDWord(FILE * file)
70 {
71         uint32 dword = 0;
72
73         for(int i=0; i<4; i++)
74         {
75                 dword <<= 8;
76                 dword |= (uint8)fgetc(file);
77         }
78
79         return dword;
80 }
81
82 //
83 // Write a WORD to the current file...
84 //
85 void WriteWord(FILE * file, uint16 word)
86 {
87         fputc(word >> 8, file);                                         // Hi byte
88         fputc(word & 0xFF, file);                                       // Lo byte
89 }
90
91 //
92 // Write a double WORD to the current file...
93 //
94 void WriteDWord(FILE * file, uint32 dword)
95 {
96         for(int i=0; i<4; i++)
97         {
98                 fputc((char)(dword >> 24), file);
99                 dword <<= 8;
100         }
101 }
102
103 /////////////////////////////////////////////////////////////////////////////
104 // Table extraction helper routines (inline 'em?)
105 ////////////////////////////////////////////////////////////////////////////
106
107 //
108 // Return a BYTE from a BYTE based table
109 //
110 uint8 GetByte(uint8 * table, uint32 &ptr)
111 {
112         return table[ptr++];
113 }
114
115 //
116 // Return a WORD from a BYTE based table
117 //
118 uint16 GetWord(uint8 * table, uint32 &ptr)
119 {
120         uint16 hi = table[ptr++];
121         uint16 lo = table[ptr++];
122
123         return (uint16)((hi<<8) | lo);
124 }
125
126 //
127 // Return a double WORD from a BYTE based table
128 //
129 uint32 GetDWord(uint8 * table, uint32 &ptr)
130 {
131         uint32 hi1 = table[ptr++];
132         uint32 lo1 = table[ptr++];
133         uint32 hi2 = table[ptr++];
134         uint32 lo2 = table[ptr++];
135
136         return (uint32)((hi1 << 24) | (lo1 << 16) | (hi2 << 8) | lo2);
137 }
138
139 /////////////////////////////////////////////////////////////////////////////
140 // Table storage helper routines (inline 'em?)
141 ////////////////////////////////////////////////////////////////////////////
142
143 //
144 // Store a BYTE in a BYTE based table
145 //
146 void SetByte(uint8 * table, uint32 &ptr, uint8 data)
147 {
148         table[ptr++] = data;
149 }
150
151 //
152 // Store a WORD in a BYTE based table
153 //
154 void SetWord(uint8 * table, uint32 &ptr, uint16 data)
155 {
156         table[ptr++] = data>>8;  table[ptr++] = data&0xFF;
157 }
158
159 //
160 // Store a DWORD in a BYTE based table
161 //
162 void SetDWord(uint8 * table, uint32 &ptr, uint32 data)
163 {
164         table[ptr++] = (uint8)(data >> 24); table[ptr++] = (uint8)(data >> 16);
165         table[ptr++] = (uint8)(data >> 8);  table[ptr++] = (uint8)(data & 0xFF);
166 }
167
168 /////////////////////////////////////////////////////////////////////////////
169 // Fixed point to float (& vice versa) conversions
170 /////////////////////////////////////////////////////////////////////////////
171 float FixedToFloat(int16 fixed)
172 {
173         return (float)fixed / 16384.0f;
174 }
175
176 /////////////////////////////////////////////////////////////////////////////
177 // TTF Constructor
178 /////////////////////////////////////////////////////////////////////////////
179 TTF::TTF(void)
180 {
181         loaded = false;                                                         // Set font initializer
182         isDirty = false;                                                        // Glyphs are clean
183         numberOfPolys = 0;                                                      // Set reasonable values
184         isCompositeGlyph = false;                                       // No composite glyph (yet)
185
186         parray[0] = &EBDT;  parray[1] = &EBLC;  parray[2] = &EBSC; // Init pointer
187         parray[3] = &LTSH;  parray[4] = &OS_2;  parray[5] = &PCLT; // array...
188         parray[6] = &VDMX;  parray[7] = &cmap;  parray[8] = &cvt; 
189         parray[9] = &fpgm;  parray[10] = &gasp; parray[11] = &glyf;
190         parray[12] = &hdmx; parray[13] = &head; parray[14] = &hhea;
191         parray[15] = &hmtx; parray[16] = &kern; parray[17] = &loca;
192         parray[18] = &maxp; parray[19] = &name; parray[20] = &post;
193         parray[21] = &prep; parray[22] = &vhea; parray[23] = &vmtx;
194
195         larray[0] = &EBDT_len;  larray[1] = &EBLC_len;  larray[2] = &EBSC_len;
196         larray[3] = &LTSH_len;  larray[4] = &OS_2_len;  larray[5] = &PCLT_len;
197         larray[6] = &VDMX_len;  larray[7] = &cmap_len;  larray[8] = &cvt_len;
198         larray[9] = &fpgm_len;  larray[10] = &gasp_len; larray[11] = &glyf_len;
199         larray[12] = &hdmx_len; larray[13] = &head_len; larray[14] = &hhea_len;
200         larray[15] = &hmtx_len; larray[16] = &kern_len; larray[17] = &loca_len;
201         larray[18] = &maxp_len; larray[19] = &name_len; larray[20] = &post_len;
202         larray[21] = &prep_len; larray[22] = &vhea_len; larray[23] = &vmtx_len;
203
204         for(uint32 i=0; i<NUMTABS; i++)
205                 *parray[i] = NULL;                                              // Init pointers...
206
207         for(uint32 i=0; i<MAXGLYPHS; i++)
208                 glyph[i] = NULL;
209 }
210
211 /////////////////////////////////////////////////////////////////////////////
212 // TTF Destructor
213 /////////////////////////////////////////////////////////////////////////////
214 TTF::~TTF()
215 {
216         ClearTables();                                                          // This should handle deallocation correctly...
217 }
218
219 /////////////////////////////////////////////////////////////////////////////
220 // Member function: void Init(void)
221 //
222 // This function initializes the TTF object, setting reasonable values for
223 // the various internal variables used by the object.
224 // [distinct from New?]
225 /////////////////////////////////////////////////////////////////////////////
226 void TTF::Init(void)
227 {
228 }
229
230 /////////////////////////////////////////////////////////////////////////////
231 // Clear the tables so that file can be reloaded
232 /////////////////////////////////////////////////////////////////////////////
233 void TTF::ClearTables(void)
234 {
235         for(uint32 i=0; i<NUMTABS; i++)
236         {
237                 if ((*parray[i]) != NULL)
238                 {
239                         free(*parray[i]);
240                         *parray[i] = NULL;
241                         *larray[i] = 0;
242                 }
243         }  
244
245         for(uint32 i=0; i<MAXGLYPHS; i++)
246         {
247                 if (glyph[i] != NULL)
248                 {
249                         free(glyph[i]);
250                         glyph[i] = NULL;
251                 }
252         }
253 }
254
255 /////////////////////////////////////////////////////////////////////////////
256 // Member function: BOOL Load(const char * filename)
257 //
258 // This loads the TTF database from an external file.  Returns 'true' if
259 // successful.
260 /////////////////////////////////////////////////////////////////////////////
261 bool TTF::Load(const char * filename)
262 {
263 //      unsigned char ch;                                                       // Temp variable
264 //      UINT num_tabs;                                                          // Number of tables
265         uint32 offset[NUMTABS], length[NUMTABS];        // Temporary storage...
266         char names[NUMTABS][5];
267         char narray[NUMTABS][5] = { "EBDT", "EBLC", "EBSC", "LTSH", "OS/2", "PCLT",
268                 "VDMX", "cmap", "cvt ", "fpgm", "gasp", "glyf", "hdmx", "head", "hhea",
269                 "hmtx", "kern", "loca", "maxp", "name", "post", "prep", "vhea", "vmtx" };
270
271         //loaded = false;
272 //      file.open(filename, ios::binary|ios::in);       // Open the file
273         FILE * file = fopen(filename, "rb");
274
275         if (file == NULL)
276 #ifdef TTFDEBUG
277 {
278 WriteLogMsg("Failed to open file!\n");
279 #endif
280                 return false;
281 #ifdef TTFDEBUG
282 }
283 #endif
284
285         if (ReadDWord(file) != 0x00010000)
286 #ifdef TTFDEBUG
287 {
288 WriteLogMsg("File was NOT a TTF file!\n");
289 #endif
290                 return false;                                                   // Not a TTF file...
291 #ifdef TTFDEBUG
292 }
293 #endif
294
295         uint32 num_tabs = ReadWord(file);                       // Get # of tables
296 #ifdef TTFDEBUG
297 WriteLogMsg("Number of tables is %u...\n", num_tabs);
298 #endif
299 //      fskip(file, 6);                                                         // Skip this shiat...
300         fseek(file, 6, SEEK_CUR);
301
302 #ifdef TTFDEBUG
303 WriteLogMsg("Reading names of tables...\n");
304 #endif
305         for(uint32 i=0; i<num_tabs; i++)
306         {
307 //              ReadFile(file, names[i], 4, &bytesRead, NULL);
308                 fread(names[i], 1, 4, file);
309                 names[i][4] = 0;
310 //              fskip(file, 4);                                                 // Checksum
311                 fseek(file, 4, SEEK_CUR);                               // Checksum
312                 offset[i] = ReadDWord(file);                    // Offset from start of file
313                 length[i] = ReadDWord(file);                    // Length of table
314         }
315
316 #ifdef TTFDEBUG
317 WriteLogMsg("Reading tables...\n");
318 #endif
319         for(uint32 i=0; i<num_tabs; i++)
320         {
321                 for(uint32 j=0; j<NUMTABS; j++)
322                 {
323                         if ((strcmp(names[i], narray[j])) == 0) // Found a match...
324                         {
325 //                              *parray[j] = (uint8 *)GlobalAlloc(GMEM_FIXED, length[i]);       // Allocate space
326                                 *parray[j] = (uint8 *)malloc(length[i]); // Alloc space
327
328                                 if (*parray[j] == NULL)
329                                         return false;                           // Bail out if nothing allocated
330
331                                 *larray[j] = length[i];                 // Set its length...
332 //                              SetFilePointer(file, (LONG)offset[i], NULL, FILE_BEGIN);
333 //                              ReadFile(file, *parray[j], length[i], &bytesRead, NULL);
334                                 fseek(file, offset[i], SEEK_SET);
335                                 fread(*parray[j], 1, length[i], file);
336                                 break;
337                         }
338                 }
339         }
340
341         fclose(file);
342
343 // This shouldn't be necessary, since it's irrelevant (loaded flag)
344 //    loaded = true;                       // Set 'loaded' flag...
345     isDirty = false;                     // Glyphs are clean
346     ExtractTables();                     // Move table data to my structs
347                                          // & ignore return val
348                                          // (should handle errors here)
349         return true;
350 }
351
352 /////////////////////////////////////////////////////////////////////////////
353 // Member function: BOOL Save(const char * filename)
354 //
355 // Save the TT font currently in the object
356 /////////////////////////////////////////////////////////////////////////////
357 bool TTF::Save(const char * filename)
358 {
359 //  fstream file;
360 //      ULONG offset = 12;
361         uint32 numtabs = 0;
362         char padding[3] = { 0, 0, 0 };
363         // Convert this to a table of ULONGs to decrease complexity...
364 //wouldn't be endian safe then...
365         char narray[NUMTABS][5] = { "EBDT", "EBLC", "EBSC", "LTSH", "OS/2", "PCLT",
366                 "VDMX", "cmap", "cvt ", "fpgm", "gasp", "glyf", "hdmx", "head", "hhea",
367                 "hmtx", "kern", "loca", "maxp", "name", "post", "prep", "vhea", "vmtx" };
368
369         if (isDirty)
370                 EncodeGlyph(currentGlyph);
371
372         BuildTables();                                                          // Ignore return value...  
373
374         for(uint32 i=0; i<NUMTABS; i++)                         // Figure out how many tables there are
375                 if ((*parray[i]) != NULL)
376                         numtabs++;
377
378         uint32 offset = 12 + (numtabs * 16);            // Calc correct offset to start of data
379
380 //      HANDLE file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
381 //              NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
382         FILE * file = fopen(filename, "wb");
383
384         WriteDWord(file, 0x00010000);                           // Write header...
385         WriteWord(file, numtabs);
386         WriteWord(file, 0);                                                     // SearchRange (Max power of 2 <= numTables) x 16.
387         WriteWord(file, 0);                                                     // entrySelector Log2(max power of 2 <= numTables).
388         WriteWord(file, 0);                                                     // NumTables x 16 - searchRange.
389
390         for(uint32 i=0; i<NUMTABS; i++)                                 // Write out table directory...
391         {
392                 if ((*parray[i]) != NULL)
393                 {
394 //                      for(int j=0; j<4; j++)
395 //                              file.put(narray[i][j]);                 // Name
396 //                      WriteFile(file, narray[i], 4, &bytesWritten, NULL);
397                         fwrite(narray[i], 1, 4, file);          // Name
398
399                         WriteDWord(file, 0);                            // Checksum
400                         WriteDWord(file, offset);                       // Offset
401                         WriteDWord(file, (*larray[i]));         // Length
402
403                         offset += (((*larray[i]) + 3) & ~3);    // Pad out to 4-uint8 boundary...
404                 }
405         }
406
407         for(uint32 i=0; i<NUMTABS; i++)                                 // Write out the tables...
408         {
409                 if ((*parray[i]) != NULL)
410                 {
411 //                      for(uint32 j=0; j<(*larray[i]); j++)
412 //                              file.put((*parray[i])[j]);
413 //                      WriteFile(file, *parray[i], *larray[i], &bytesWritten, NULL);
414                         fwrite(*parray[i], 1, *larray[i], file);
415
416                         uint32 remainder = ((*larray[i]) & 0x3);
417                         if (remainder)               // i.e., it's not evenly div by 4
418 //                              for(j=remainder; j<4; j++)
419 //                                      file.put((char)0);       // pad it!
420 //                              WriteFile(file, padding, 4 - remainder, &bytesWritten, NULL);
421                                 fwrite(padding, 1, 4 - remainder, file);
422                 }
423         }
424
425         fclose(file);
426
427         return true;                                                            // Whether or not it was successful...
428 }
429
430 /////////////////////////////////////////////////////////////////////////////
431 // Member function: BOOL EncodeGlyph(int glyphnum)
432 //
433 // This function encodes the glyph data and stores it to the 'glyf' table.
434 /////////////////////////////////////////////////////////////////////////////
435 bool TTF::EncodeGlyph(uint16 glyphnum)
436 {
437         bool retval = false;                                            // Assume failure
438         uint8 flag, xbuf[4000], ybuf[4000], fbuf[2000];
439         uint32 xp = 0, yp = 0, fp = 0;                          // Table pointers
440
441         if (glyphnum < myMaxp.numGlyphs)  // numofgls is 1 based ind, glyph# 0 based
442         {
443                 // need to add composite encoding...
444                 int lastx = 0, lasty = 0;
445
446                 for(uint32 i=0; i<numberOfPoints; i++)
447                 {
448                         flag = 0;
449                         int curx = gx[i] - lastx, cury = gy[i] - lasty;
450
451                         if (onCurve[i])
452                                 flag |= 0x01;                                   // Set on curve info
453
454                         if (curx)
455                         {
456                                 if ((curx > 255) || (curx < -255)) // I.e., it's 2 uint8 value
457                                         SetWord(xbuf, xp, curx);
458                                 else
459                                 {
460                                         if (curx & 0x100)
461                                         {
462                                                 flag |= 0x02; // I.e., it's negative
463                                                 curx *= -1;   // Flip it so correct value is stored
464                                         }
465                                         else
466                                                 flag |= 0x12;
467
468                                         SetByte(xbuf, xp, curx);        // Automagically strips neg bit
469                                 }
470                         }
471                         else
472                                 flag |= 0x10;                                   // X-coord is same...
473   
474                         if (cury)
475                         {
476                                 if ((cury > 255) || (cury < -255)) // I.e., it's 2 uint8 value
477                                         SetWord(ybuf, yp, cury);
478                                 else
479                                 {
480                                         if (cury & 0x100)
481                                         {
482                                                 flag |= 0x04; // I.e., it's negative
483                                                 cury *= -1;
484                                         }
485                                         else
486                                                 flag |= 0x24;
487             
488                                         SetByte(ybuf, yp, cury);
489                                 }
490                         }
491                         else
492                                 flag |= 0x20;                 // Y-coord is same...
493   
494                         fbuf[i] = flag;
495                         lastx = gx[i];  lasty = gy[i];
496                 }
497
498                 // Now crunch flags...  ugly, ugly, ugly.
499 /*
500     fbuf[numberOfPoints] = 0;  // Set sentinel value (ugly way to do this)
501     for(i=0; i<numberOfPoints; i++);
502     {
503       if (fbuf[i] == fbuf[i+1])  // 
504       {
505         uint8 count = 0;  // Sentinel takes care of check for end of flags...
506         while (fbuf[i] == fbuf[++i])  count++; // Count number of repeats
507         i--;
508         fbuf[fp++] = fbuf[i] | 0x08; // Set repeat flag
509         fbuf[fp++] = count;          // & number of repeats
510       }
511       else  fbuf[fp++] = fbuf[i];    // Otherwise, just copy...
512     }
513 */
514                 fp = numberOfPoints;
515                 // Find length of glyph and reallocate space if necessary
516
517                 uint32 newLength = 12 + numberOfPolys*2 + numberOfHints + fp + xp + yp;
518
519                 if (newLength & 0x03)
520                         newLength += (4 - newLength & 0x03);
521
522                 if (glyphLen[glyphnum] != newLength)
523                 {
524                         glyph[glyphnum] = (uint8 *)realloc(glyph[glyphnum], newLength);
525                         glyphLen[glyphnum] = newLength;
526                 }
527
528                 // And finally, store it!
529
530                 uint32 gp = 0;                                                  // Glyph pointer...
531                 SetWord(glyph[glyphnum], gp, numberOfPolys);
532                 SetWord(glyph[glyphnum], gp, llx);
533                 SetWord(glyph[glyphnum], gp, lly);
534                 SetWord(glyph[glyphnum], gp, urx);
535                 SetWord(glyph[glyphnum], gp, ury);
536                 for(uint32 i=0; i<numberOfPolys; i++)
537                         SetWord(glyph[glyphnum], gp, poly[i]);
538                 SetWord(glyph[glyphnum], gp, numberOfHints);
539                 for(uint32 i=0; i<numberOfHints; i++)
540                         SetByte(glyph[glyphnum], gp, hint[i]);
541                 for(uint32 i=0; i<fp; i++)
542                         SetByte(glyph[glyphnum], gp, fbuf[i]);
543                 for(uint32 i=0; i<xp; i++)
544                         SetByte(glyph[glyphnum], gp, xbuf[i]);
545                 for(uint32 i=0; i<yp; i++)
546                         SetByte(glyph[glyphnum], gp, ybuf[i]);
547
548                 retval = true;                                                  // Successfully encoded!
549         }
550
551         return retval;
552 }
553
554 /////////////////////////////////////////////////////////////////////////////
555 // Member function: BOOL DecodeGlyph(int glyphnum)
556 //
557 // This function decodes the glyph data and stores it to the object's
558 // internal array.
559 /////////////////////////////////////////////////////////////////////////////
560 bool TTF::DecodeGlyph(uint16 glyphnum)
561 {
562         bool retval = false;
563         uint32 i, dp;
564
565         // glyphnum is 0 based index, while numGlyphs is 1 based
566         if (glyphnum >= myMaxp.numGlyphs)
567                 return false;  // Invalid char #
568
569         if (!glyphLen[glyphnum])
570         {
571                 numberOfPoints = numberOfPolys = 0;
572                 return true;                                                    // Zero length IS valid...
573         }
574 //      else                                                                            // Get character data...
575 //      {
576     // Now get the character data...
577         dp = 0;                     // Reset data pointer
578         isCompositeGlyph = false;   // Default is no
579         numberOfPolys = GetWord(glyph[glyphnum], dp);  // # of polygons
580
581         llx = (int16)GetWord(glyph[glyphnum], dp);           // Lower left X
582         lly = (int16)GetWord(glyph[glyphnum], dp);           // Lower left Y
583         urx = (int16)GetWord(glyph[glyphnum], dp);           // Upper right X
584         ury = (int16)GetWord(glyph[glyphnum], dp);           // Upper right Y
585
586         // Need to handle composite glyphs better here.  The ways things
587         // are set now is a recipe for disaster...
588
589         if (numberOfPolys == 0xFFFF)
590         {
591                 isCompositeGlyph = true;
592                 numberOfPolys = 0;                                              // Set for no points
593
594                 Composite cmpst;
595
596                 while (!compositeList.IsEmpty())                // Empty composite list...
597                         compositeList.GetFront();
598
599                 do
600                 {
601                         cmpst.flags = GetWord(glyph[glyphnum], dp);
602                         cmpst.glyphIndex = GetWord(glyph[glyphnum], dp);
603                         cmpst.arg1 = (cmpst.flags & 0x01 ? (int16)GetWord(glyph[glyphnum], dp) : (int8)GetByte(glyph[glyphnum], dp));
604                         cmpst.arg2 = (cmpst.flags & 0x01 ? (int16)GetWord(glyph[glyphnum], dp) : (int8)GetByte(glyph[glyphnum], dp));
605
606                         if (cmpst.flags & 0x08)
607                                 cmpst.xScale = cmpst.yScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp));
608                         else if (cmpst.flags & 0x40)
609                                 cmpst.xScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp)),
610                                 cmpst.yScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp));
611                         else if (cmpst.flags & 0x80)
612                                 cmpst.xScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp)),
613                                 cmpst.scale01 = FixedToFloat((int16)GetWord(glyph[glyphnum], dp)),
614                                 cmpst.scale10 = FixedToFloat((int16)GetWord(glyph[glyphnum], dp)),
615                                 cmpst.yScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp));
616
617                         compositeList.AddAtRear(cmpst);
618                 }
619                 while (cmpst.flags & 0x20); //*/
620
621                 return true;
622         }
623
624 //do {
625 //      USHORT flags;
626 //      USHORT glyphIndex;
627 //      if ( flags & ARG_1_AND_2_ARE_uint16S) {
628 //      (SHORT or Fuint16) argument1;
629 //      (SHORT or Fuint16) argument2;
630 //      } else {
631 //              USHORT arg1and2; /* (arg1 << 8) | arg2 */
632 //      }
633 //      if ( flags & WE_HAVE_A_SCALE ) {
634 //              F2Dot14  scale;    /* Format 2.14 */
635 //      } else if ( flags & WE_HAVE_AN_X_AND_Y_SCALE ) {
636 //              F2Dot14  xscale;    /* Format 2.14 */
637 //              F2Dot14  yscale;    /* Format 2.14 */
638 //      } else if ( flags & WE_HAVE_A_TWO_BY_TWO ) {
639 //              F2Dot14  xscale;    /* Format 2.14 */
640 //              F2Dot14  scale01;   /* Format 2.14 */
641 //              F2Dot14  scale10;   /* Format 2.14 */
642 //              F2Dot14  yscale;    /* Format 2.14 */
643 //      }
644 //} while ( flags & MORE_COMPONENTS ) 
645 //if (flags & WE_HAVE_INSTR){
646 //      USHORT numInstr
647 //      uint8 instr[numInstr]
648 //
649 //Flags                    Bit     Description 
650 //ARG_1_AND_2_ARE_uint16S    0       If this is set, the arguments are uint16s;
651 //                                 otherwise, they are uint8s.
652 //ARGS_ARE_XY_VALUES       1       If this is set, the arguments are xy values;
653 //                                 otherwise, they are points.
654 //ROUND_XY_TO_GRID         2       For the xy values if the preceding is true.
655 //WE_HAVE_A_SCALE          3       This indicates that there is a simple scale
656 //                                 for the component. Otherwise, scale = 1.0.
657 //RESERVED                 4       This bit is reserved.  Set it to 0. 
658 //MORE_COMPONENTS          5       Indicates at least one more glyph after this
659 //                                 one.
660 //WE_HAVE_AN_X_AND_Y_SCALE 6       The x direction will use a different scale
661 //                                 from the y direction.
662 //WE_HAVE_A_TWO_BY_TWO     7       There is a 2 by 2 transformation that will
663 //                                 be used to scale the component.
664 //WE_HAVE_INSTRUCTIONS     8       Following the last component are
665 //                                 instructions for the composite character.
666 //USE_MY_METRICS           9       If set, this forces the aw and lsb (and rsb)
667 //                                 for the composite to be equal to those from
668 //                                 this original glyph. This works for hinted
669 //                                 and unhinted characters.
670
671         for(i=0; i<numberOfPolys; i++)
672                 poly[i] = GetWord(glyph[glyphnum], dp);
673
674         numberOfHints = GetWord(glyph[glyphnum], dp);
675
676         for(i=0; i<numberOfHints; i++)
677                 hint[i] = GetByte(glyph[glyphnum], dp);
678
679         // Decode the dots...
680
681         uint32 num_pts = poly[numberOfPolys-1] + 1;
682         numberOfPoints = num_pts; // necessary??
683         uint32 xptr, yptr;        // pointers to beginning of coord data
684         uint32 numXs = 0;
685         int xx = 0, yy = 0, repeat;
686         uint32 numTokens = num_pts, k, numRep;
687
688         // We make an educated guess that num_pts = num_tokens; but if there
689         // is repeated data in the tokens, then we need to adjust the # of
690         // tokens down appropriately.
691
692         for(uint32 i=0; i<numTokens; i++)
693         {
694                 uint8 token = glyph[glyphnum][dp+i];  uint32 rpts = 1;
695
696                 if (token & 0x08)      // Repeated token?
697                 {
698                         i++;                 // Yes, bump pointer to # of times to repeat
699                         numRep = glyph[glyphnum][dp+i];
700                         rpts += numRep;
701
702                         if (numRep > 1)      // Do we need to adjust numTokens?
703    // this is bad, modifying numTokens while it's used as a compare value
704    // in the above loop...
705    // Is it necessary to do so in order to keep from going too far?
706                         numTokens -= (numRep - 1); // Yes, adjust.
707                 }
708
709                 // 10 = same x(0uint8s), 00 = 2uint8s, 02&12 = 1uint8
710                 if ((token & 0x02) == 0x02)
711                         numXs += rpts;
712
713                 if ((token & 0x12) == 0x00)
714                         numXs += (rpts*2);
715         }
716
717         xptr = dp + numTokens;
718         yptr = dp + numTokens + numXs;
719
720         // & continue decoding X/Y-coords...
721
722         k = 0;                               // Index to the point array
723
724         for(uint32 i=0; i<numTokens; i++)
725         {
726                 uint8 token = glyph[glyphnum][dp+i];
727                 repeat = 1;
728
729                 if (token & 0x08)
730                 {
731                         i++;
732                         repeat += glyph[glyphnum][dp+i]; // Set repeat data...
733                 }
734
735                 while (repeat--)
736                 {
737                         if ((token & 0x12) == 0x12)
738                                 xx += GetByte(glyph[glyphnum], xptr);
739
740                         if ((token & 0x12) == 0x02)
741                                 xx -= GetByte(glyph[glyphnum], xptr);
742
743                         if ((token & 0x12) == 0x00)
744                                 xx += (int16)GetWord(glyph[glyphnum], xptr);
745
746                         gx[k] = xx;                      // Store x-coordinate
747
748                         if ((token & 0x24) == 0x24)
749                                 yy += GetByte(glyph[glyphnum], yptr);
750
751                         if ((token & 0x24) == 0x04)
752                                 yy -= GetByte(glyph[glyphnum], yptr);
753
754                         if ((token & 0x24) == 0x00)
755                                 yy += (int16)GetWord(glyph[glyphnum], yptr);
756
757                         gy[k] = yy;                      // Store y-coordinate
758
759                         onCurve[k++] = (token & 0x01 ? true : false);  // If bit 0 set, then it's on curve
760                 }
761         }
762
763         retval = true;                                                  // Hmm. Successfully decoded a glyph...
764 //      }
765
766         isDirty = false;  // do it here?
767
768         return retval;
769 }
770
771 /*****************************************************************************
772  Member function:
773
774  This function decodes the 'glyf' data for a non-composite (atomic) glyph and
775  returns it as a GlyphPoints object. Helper function.
776  *****************************************************************************/
777 GlyphPoints TTF::GetGlyphPoints(uint16 glyphNum)
778 {
779         if (DecodeGlyph(glyphNum))
780                 return GlyphPoints(numberOfPoints, numberOfPolys, gx, gy, onCurve, poly);
781
782         return GlyphPoints();
783 }
784
785 /*****************************************************************************
786  Member function:
787
788  This function decodes the 'glyf' data for a composite glyph and returns
789  it as a GlyphPoints object.
790  *****************************************************************************/
791 GlyphPoints TTF::GetAllCompositePoints(uint16 glyphNum)
792 {
793 //  int tmpGlyph = currentGlyph;
794   
795         DecodeGlyph(glyphNum);         // Check for composite-ness
796
797         if (!isCompositeGlyph)
798                 return GlyphPoints();
799
800 /*
801   for(int i=1; i<=pDoc->m_myFont.compositeList.Length(); i++)
802   {
803     TComposite cmpst = fnt->compositeList.PeekPosition(i);
804     fnt->SetGlyph(cmpst.glyphIndex);
805     if (cmpst.flags & 0x0002)
806       m_nXOffset = cmpst.arg1, m_nYOffset = cmpst.arg2;
807     ScanConvertSingleGlyph(pDC, nScanlines, nHorzLines, nXOffset, nYOffset);
808   }
809   fnt->SetGlyph(pDoc->character_num);
810 */
811
812         GlyphPoints retVal;
813
814         for(int i=1; i<=compositeList.Length(); i++)
815         {
816                 Composite cmpst = compositeList.PeekPosition(i);
817     
818 //    SetGlyph(cmpst.glyphIndex);
819 //    if (cmpst.flags & 0x0002)
820 //      m_nXOffset = cmpst.arg1, m_nYOffset = cmpst.arg2;
821 //    ScanConvertSingleGlyph(pDC, nScanlines, nHorzLines, nXOffset, nYOffset);
822                 GlyphPoints gp = GetGlyphPoints(cmpst.glyphIndex);
823
824                 if (cmpst.flags & 0x0002)
825                         gp.OffsetPoints(cmpst.arg1, cmpst.arg2);
826
827                 retVal = retVal + gp;
828                 // NOTE: May have to adjust scanlines as per 0x0002 above...
829         }
830
831 //  SetGlyph(tmpGlyph);
832         DecodeGlyph(currentGlyph);     // Reset needed here...
833
834         return retVal;
835 }
836
837 /////////////////////////////////////////////////////////////////////////////
838 // Member function: void GetCharName(int cNum, uint8 * buf)
839 //
840 // This function returns the character name of the glyph number passed in.
841 /////////////////////////////////////////////////////////////////////////////
842 void TTF::GetCharName(int cNum, uint8 * buf)
843 {
844         buf[0] = 0;                                                                     // Set failure as default condition
845   
846         if (!post)                                                                      // PS names are here...
847                 return;
848
849         if (post[1] != 0x02 || post[2] != 0x00)         // i.e., it's NOT a V2.0 table
850                 return;
851
852         uint8 * pTab = NULL;
853         uint32 tabOff = 34, numGlyphs = (uint32)((post[32] << 8) | post[33]);
854         uint32 index = (uint32)((post[tabOff + cNum * 2] << 8) | post[tabOff + cNum * 2 + 1]);
855         uint32 nInd2;
856
857         if (index > 257)
858         {
859                 index -= 258;
860                 nInd2 = tabOff + (2 * numGlyphs);
861                 pTab = post;
862         }
863         else
864         {
865                 nInd2 = 0;
866                 pTab = macStdNames;
867         }
868
869         for(uint32 i=0; i<index; i++)
870                 nInd2 = nInd2 + pTab[nInd2] + 1; // 1st uint8 is length of string + that uint8
871
872         uint8 len = pTab[nInd2];
873         nInd2++;
874
875         for(uint8 i=0; i<len; i++)
876                 buf[i] = pTab[nInd2 + i];
877
878         buf[len] = 0;
879 }
880
881 /////////////////////////////////////////////////////////////////////////////
882 // Member function: BOOL ExtractTables(void)
883 //
884 // This function extracts the data from the various tables and puts them in
885 // various structs for easier handling of the font data.
886 /////////////////////////////////////////////////////////////////////////////
887 bool TTF::ExtractTables(void)
888 {
889         if (head_len != 54)
890         {
891 #ifdef TTFDEBUG
892 WriteLogMsg("Bad HEAD header: Expected 54, found %u...\n", head_len);
893 #endif
894                 return false;                                                   // Corrupt data?
895         }
896
897         uint32 tp = 0;
898         myHead.version            = GetDWord(head, tp);
899         myHead.fontRevision       = GetDWord(head, tp);
900         myHead.checkSumAdjustment = GetDWord(head, tp);
901         myHead.magicNumber        = GetDWord(head, tp);
902         myHead.flags              = GetWord(head, tp);
903         myHead.unitsPerEm         = GetWord(head, tp);
904         myHead.createdh           = GetDWord(head, tp);
905         myHead.createdl           = GetDWord(head, tp);
906         myHead.modifiedh          = GetDWord(head, tp);
907         myHead.modifiedl          = GetDWord(head, tp);
908         myHead.xMin               = GetWord(head, tp);
909         myHead.yMin               = GetWord(head, tp);
910         myHead.xMax               = GetWord(head, tp);
911         myHead.yMax               = GetWord(head, tp);
912         myHead.macStyle           = GetWord(head, tp);
913         myHead.lowestRecPPEM      = GetWord(head, tp);
914         myHead.fontDirectionHint  = (int16)GetWord(head, tp);
915         myHead.indexToLocFormat   = (int16)GetWord(head, tp);
916         myHead.glyphDataFormat    = (int16)GetWord(head, tp);
917
918         if (maxp_len != 32)
919         {
920 #ifdef TDEBUG
921 WriteLogMsg("Bad MAXP header: Expected 32, found %u...\n", maxp_len);
922 #endif
923                 return false;                                                   // Corrupt data?
924         }
925
926         tp = 0;                                                                         // Reset table pointer
927         myMaxp.version               = GetDWord(maxp, tp);
928         myMaxp.numGlyphs             = GetWord(maxp, tp);
929         myMaxp.maxPoints             = GetWord(maxp, tp);
930         myMaxp.maxContours           = GetWord(maxp, tp);
931         myMaxp.maxCompositePoints    = GetWord(maxp, tp);
932         myMaxp.maxCompositeContours  = GetWord(maxp, tp);
933         myMaxp.maxZones              = GetWord(maxp, tp);
934         myMaxp.maxTwilightPoints     = GetWord(maxp, tp);
935         myMaxp.maxStorage            = GetWord(maxp, tp);
936         myMaxp.maxFunctionDefs       = GetWord(maxp, tp);
937         myMaxp.maxInstructionDefs    = GetWord(maxp, tp);
938         myMaxp.maxStackElements      = GetWord(maxp, tp);
939         myMaxp.maxSizeOfInstructions = GetWord(maxp, tp);
940         myMaxp.maxComponentElements  = GetWord(maxp, tp);
941         myMaxp.maxComponentDepth     = GetWord(maxp, tp);
942
943         tp = 0;                                                                         // Reset table pointer
944         uint32 start = (myHead.indexToLocFormat ? GetDWord(loca, tp) : GetWord(loca, tp) << 1);
945
946         for(uint32 i=0; i<myMaxp.numGlyphs; i++)
947         {
948                 uint32 end = (myHead.indexToLocFormat ? GetDWord(loca, tp) : GetWord(loca, tp) << 1);
949                 uint32 length = end - start;
950                 glyphLen[i] = length;                                   // Lengths are saved 'cause malloc is sloppy
951
952                 if (length)     // loca+start? pointer arithmetic?
953                 {
954                         glyph[i] = (uint8 *)malloc(length);     // Allocate space,
955                         memcpy(glyph[i], glyf+start, length);   // and move it!
956                 }
957                 else
958                         glyph[i] = NULL;
959
960                 start = end;                                                    // Reset start value
961         }
962
963         return true;
964 }
965
966 /////////////////////////////////////////////////////////////////////////////
967 // Member function: BOOL BuildTables(void)
968 //
969 // This function builds the various TTF tables using info in the various
970 // structs so that a TTF file can be written out to disk.
971 /////////////////////////////////////////////////////////////////////////////
972 bool TTF::BuildTables(void)
973 {
974         uint32 i, tp, start;
975
976         myHead.indexToLocFormat = 1;                            // We don't bother with [uint16s*2] format...
977
978         // Build HEAD table
979
980         tp = 0;                                                                         // Reset table pointer
981         SetDWord(head, tp, myHead.version);//            = GetDWord(head, tp);
982         SetDWord(head, tp, myHead.fontRevision);//       = GetDWord(head, tp);
983         SetDWord(head, tp, myHead.checkSumAdjustment);// = GetDWord(head, tp);
984         SetDWord(head, tp, myHead.magicNumber);//        = GetDWord(head, tp);
985         SetWord(head, tp, myHead.flags);//              = GetWord(head, tp);
986         SetWord(head, tp, myHead.unitsPerEm);//         = GetWord(head, tp);
987         SetDWord(head, tp, myHead.createdh);//           = GetDWord(head, tp);
988         SetDWord(head, tp, myHead.createdl);//           = GetDWord(head, tp);
989         SetDWord(head, tp, myHead.modifiedh);//          = GetDWord(head, tp);
990         SetDWord(head, tp, myHead.modifiedl);//          = GetDWord(head, tp);
991         SetWord(head, tp, myHead.xMin);//               = GetWord(head, tp);
992         SetWord(head, tp, myHead.yMin);//               = GetWord(head, tp);
993         SetWord(head, tp, myHead.xMax);//               = GetWord(head, tp);
994         SetWord(head, tp, myHead.yMax);//               = GetWord(head, tp);
995         SetWord(head, tp, myHead.macStyle);//           = GetWord(head, tp);
996         SetWord(head, tp, myHead.lowestRecPPEM);//      = GetWord(head, tp);
997         SetWord(head, tp, myHead.fontDirectionHint);//  = (int16)GetWord(head, tp);
998         SetWord(head, tp, myHead.indexToLocFormat);//   = (int16)GetWord(head, tp);
999         SetWord(head, tp, myHead.glyphDataFormat);//    = (int16)GetWord(head, tp);
1000
1001         // Build MAXP table
1002
1003         tp = 0;                                                                         // Reset table pointer
1004         SetDWord(maxp, tp, myMaxp.version);//               = GetDWord(maxp, tp);
1005         SetWord(maxp, tp, myMaxp.numGlyphs);//             = GetWord(maxp, tp);
1006         SetWord(maxp, tp, myMaxp.maxPoints);//             = GetWord(maxp, tp);
1007         SetWord(maxp, tp, myMaxp.maxContours);//           = GetWord(maxp, tp);
1008         SetWord(maxp, tp, myMaxp.maxCompositePoints);//    = GetWord(maxp, tp);
1009         SetWord(maxp, tp, myMaxp.maxCompositeContours);//  = GetWord(maxp, tp);
1010         SetWord(maxp, tp, myMaxp.maxZones);//              = GetWord(maxp, tp);
1011         SetWord(maxp, tp, myMaxp.maxTwilightPoints);//     = GetWord(maxp, tp);
1012         SetWord(maxp, tp, myMaxp.maxStorage);//            = GetWord(maxp, tp);
1013         SetWord(maxp, tp, myMaxp.maxFunctionDefs);//       = GetWord(maxp, tp);
1014         SetWord(maxp, tp, myMaxp.maxInstructionDefs);//    = GetWord(maxp, tp);
1015         SetWord(maxp, tp, myMaxp.maxStackElements);//      = GetWord(maxp, tp);
1016         SetWord(maxp, tp, myMaxp.maxSizeOfInstructions);// = GetWord(maxp, tp);
1017         SetWord(maxp, tp, myMaxp.maxComponentElements);//  = GetWord(maxp, tp);
1018         SetWord(maxp, tp, myMaxp.maxComponentDepth);//     = GetWord(maxp, tp);
1019
1020         // Build LOCA & GLYF tables
1021
1022         loca_len = (myMaxp.numGlyphs+1) * 4;            // Set size of table
1023
1024         if (loca)
1025                 free(loca);                                                             // And create/reallocate it...
1026
1027         loca = (uint8 *) malloc(loca_len);
1028
1029         glyf_len = 0;                                                           // Refigure glyf table length
1030
1031         for(i=0; i<myMaxp.numGlyphs; i++)
1032                 glyf_len += glyphLen[i];
1033
1034         if (glyf)
1035                 free(glyf);
1036
1037         glyf = (uint8 *) malloc(glyf_len);
1038
1039         start = tp = 0;                                                         // Reset table pointer
1040
1041         for(i=0; i<myMaxp.numGlyphs; i++)
1042         {
1043                 SetDWord(loca, tp, start);                              // Store glyph start address
1044
1045                 if (glyphLen[i])
1046                         memcpy(glyf+start, glyph[i], glyphLen[i]);
1047
1048                 start += glyphLen[i];
1049         }
1050
1051         SetDWord(loca, tp, start);                                      // Finally, store end of glyphs+1
1052
1053         return true;
1054 }
1055
1056 /////////////////////////////////////////////////////////////////////////////
1057 // Member function: BOOL SetGlyph(int glyphnum)
1058 //
1059 // This function decodes the glyph data and stores the points in its own
1060 // internal array.  If the flag isDirty is set, it also encodes the internal
1061 // array and stores it to the 'glyf' table.
1062 /////////////////////////////////////////////////////////////////////////////
1063 bool TTF::SetGlyph(uint16 glyphnum)
1064 {
1065         bool retval = false;                                            // Set failure as default
1066
1067         if (isDirty)
1068                 EncodeGlyph(currentGlyph);
1069
1070         isDirty = false;
1071
1072         if (glyphnum < myMaxp.numGlyphs)                        // numofgls is 1 based ind, glyph# 0 based
1073         {
1074                 currentGlyph = glyphnum;
1075                 DecodeGlyph(currentGlyph);
1076                 retval = true;
1077         }
1078
1079         return retval;
1080 }
1081
1082 /////////////////////////////////////////////////////////////////////////////
1083 // Member function: BOOL AddGlyph(int glyphnum)
1084 //
1085 // This function adds a glyph of zero size at position glyphnum.  If glyphnum
1086 // is greater than the number of glyphs, glyph is added at end of list. This
1087 // glyph then becomes the current glyph.
1088 /////////////////////////////////////////////////////////////////////////////
1089 bool TTF::AddGlyph(uint16 glyphnum)
1090 {
1091         // incomplete: JLH
1092         bool retval = false;
1093
1094         if (isDirty)
1095                 EncodeGlyph(currentGlyph);
1096
1097         isDirty = false;
1098
1099         return retval;
1100 }
1101
1102 /////////////////////////////////////////////////////////////////////////////
1103 // Member function: BOOL DeleteGlyph(int glyphnum)
1104 //
1105 // This function deletes the glyph at position glyphnum.  All glyphs after
1106 // this glyph are moved down in position.
1107 /////////////////////////////////////////////////////////////////////////////
1108 bool TTF::DeleteGlyph(uint16 glyphnum)
1109 {
1110         // incomplete: JLH
1111         bool retval = false;
1112
1113         return retval;
1114 }
1115
1116 //
1117 // Various & sundry member functions implementation
1118 //
1119 // NOTE: For error handling, should throw exceptions--not return values...! !!! FIX !!!
1120 //
1121
1122 Box TTF::GetBoundingBox(void)
1123 {
1124         return Box(llx, lly, urx, ury);
1125 }
1126
1127 GlyphPt TTF::GetPoint(uint16 pointno)
1128 {
1129         GlyphPt p;
1130
1131         if (pointno >= MAXPOINTS)
1132                 return p; // Fix to make invalid
1133
1134         p.x = gx[pointno], p.y = gy[pointno], p.onCurve = onCurve[pointno];
1135         return p;
1136 }
1137
1138 uint16 TTF::GetNumberOfPolys(void)
1139 {
1140         return numberOfPolys;
1141 }
1142
1143 uint16 TTF::GetPolyEnd(uint16 polynum)
1144 {
1145         if (polynum >= numberOfPolys)
1146                 return 0;
1147
1148         return poly[polynum];
1149 }
1150
1151 int TTF::GetPointX(uint16 pointno)
1152 {
1153         if (pointno >= MAXPOINTS)
1154                 return 0;
1155
1156         return gx[pointno];
1157 }
1158
1159 int TTF::GetPointY(uint16 pointno)
1160 {
1161         if (pointno >= MAXPOINTS)
1162                 return 0;
1163
1164         return gy[pointno];
1165 }
1166
1167 bool TTF::GetOnCurve(uint16 pointno)
1168 {
1169         if (pointno >= MAXPOINTS)
1170                 return true;
1171
1172         return onCurve[pointno];
1173 }
1174
1175 bool TTF::SetOnCurve(uint16 pointno, bool state)
1176 {
1177         if (pointno >= numberOfPoints)
1178                 return false;
1179
1180         onCurve[pointno] = state;
1181         isDirty = true;
1182
1183         return true;
1184 }
1185
1186 bool TTF::MovePoint(uint16 pointno, int x, int y)
1187 {
1188         if (pointno >= numberOfPoints)
1189                 return false;
1190
1191         gx[pointno] = x;  gy[pointno] = y;
1192         isDirty = true;
1193
1194         return true;
1195 }
1196
1197 bool TTF::MovePoint(uint16 pointno, GlyphPt p)
1198 {
1199         if (pointno >= numberOfPoints)
1200                 return false;
1201
1202         gx[pointno] = p.x;  gy[pointno] = p.y;  onCurve[pointno] = p.onCurve;
1203         isDirty = true;
1204
1205         return true;
1206 }
1207
1208 bool TTF::IsCompositeGlyph(void)
1209 {
1210         return isCompositeGlyph;
1211 }
1212