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