2 // TTF.CPP - The TrueType class
\r
3 // by James L. Hammons
\r
4 // (C) 2005 Underground Software
\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
11 // JLH = James L. Hammons <jlhamm@acm.org>
\r
14 // --- ---------- -------------------------------------------------------------
\r
15 // JLH ??/??/199? Created this file
\r
18 // STILL TO BE DONE:
\r
20 // - Eliminate ALL references to BYTE, WORD, SBYTE, SWORD, etc.
\r
23 #include <stdio.h> // For file handling, etc. //
\r
26 #include "charnames.h"
\r
35 #define NUMTABS 24 // Number of distinct tables
\r
38 /*void fskip(HANDLE file, uint32 bytesToSkip)
\r
40 SetFilePointer(file, (LONG)bytesToSkip, NULL, FILE_CURRENT);
\r
44 // Get a BYTE from the current file...
\r
46 uint8 ReadByte(FILE * file)
\r
48 return (uint8)fgetc(file);
\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
56 // Get a WORD from the current file...
\r
58 uint16 ReadWord(FILE * file)
\r
60 uint16 word = (uint16)fgetc(file) << 8;
\r
61 word |= (uint16)fgetc(file);
\r
67 // Get a double WORD from the current file...
\r
69 uint32 ReadDWord(FILE * file)
\r
73 for(int i=0; i<4; i++)
\r
76 dword |= (uint8)fgetc(file);
\r
83 // Write a WORD to the current file...
\r
85 void WriteWord(FILE * file, uint16 word)
\r
87 fputc(word >> 8, file); // Hi byte
\r
88 fputc(word & 0xFF, file); // Lo byte
\r
92 // Write a double WORD to the current file...
\r
94 void WriteDWord(FILE * file, uint32 dword)
\r
96 for(int i=0; i<4; i++)
\r
98 fputc((char)(dword >> 24), file);
\r
103 /////////////////////////////////////////////////////////////////////////////
\r
104 // Table extraction helper routines (inline 'em?)
\r
105 ////////////////////////////////////////////////////////////////////////////
\r
108 // Return a BYTE from a BYTE based table
\r
110 uint8 GetByte(uint8 * table, uint32 &ptr)
\r
112 return table[ptr++];
\r
116 // Return a WORD from a BYTE based table
\r
118 uint16 GetWord(uint8 * table, uint32 &ptr)
\r
120 uint16 hi = table[ptr++];
\r
121 uint16 lo = table[ptr++];
\r
123 return (uint16)((hi<<8) | lo);
\r
127 // Return a double WORD from a BYTE based table
\r
129 uint32 GetDWord(uint8 * table, uint32 &ptr)
\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
136 return (uint32)((hi1 << 24) | (lo1 << 16) | (hi2 << 8) | lo2);
\r
139 /////////////////////////////////////////////////////////////////////////////
\r
140 // Table storage helper routines (inline 'em?)
\r
141 ////////////////////////////////////////////////////////////////////////////
\r
144 // Store a BYTE in a BYTE based table
\r
146 void SetByte(uint8 * table, uint32 &ptr, uint8 data)
\r
148 table[ptr++] = data;
\r
152 // Store a WORD in a BYTE based table
\r
154 void SetWord(uint8 * table, uint32 &ptr, uint16 data)
\r
156 table[ptr++] = data>>8; table[ptr++] = data&0xFF;
\r
160 // Store a DWORD in a BYTE based table
\r
162 void SetDWord(uint8 * table, uint32 &ptr, uint32 data)
\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
168 /////////////////////////////////////////////////////////////////////////////
\r
169 // Fixed point to float (& vice versa) conversions
\r
170 /////////////////////////////////////////////////////////////////////////////
\r
171 float FixedToFloat(int16 fixed)
\r
173 return (float)fixed / 16384.0f;
\r
176 /////////////////////////////////////////////////////////////////////////////
\r
178 /////////////////////////////////////////////////////////////////////////////
\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
186 parray[0] = &EBDT; parray[1] = &EBLC; parray[2] = &EBSC; // Init pointer
\r
187 parray[3] = <SH; 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
195 larray[0] = &EBDT_len; larray[1] = &EBLC_len; larray[2] = &EBSC_len;
\r
196 larray[3] = <SH_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
204 for(uint32 i=0; i<NUMTABS; i++)
\r
205 *parray[i] = NULL; // Init pointers...
\r
207 for(uint32 i=0; i<MAXGLYPHS; i++)
\r
211 /////////////////////////////////////////////////////////////////////////////
\r
213 /////////////////////////////////////////////////////////////////////////////
\r
216 ClearTables(); // This should handle deallocation correctly...
\r
219 /////////////////////////////////////////////////////////////////////////////
\r
220 // Member function: void Init(void)
\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
230 /////////////////////////////////////////////////////////////////////////////
\r
231 // Clear the tables so that file can be reloaded
\r
232 /////////////////////////////////////////////////////////////////////////////
\r
233 void TTF::ClearTables(void)
\r
235 for(uint32 i=0; i<NUMTABS; i++)
\r
237 if ((*parray[i]) != NULL)
\r
245 for(uint32 i=0; i<MAXGLYPHS; i++)
\r
247 if (glyph[i] != NULL)
\r
255 /////////////////////////////////////////////////////////////////////////////
\r
256 // Member function: BOOL Load(const char * filename)
\r
258 // This loads the TTF database from an external file. Returns 'true' if
\r
260 /////////////////////////////////////////////////////////////////////////////
\r
261 bool TTF::Load(const char * filename)
\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
272 // file.open(filename, ios::binary|ios::in); // Open the file
\r
273 FILE * file = fopen(filename, "rb");
\r
278 WriteLogMsg("Failed to open file!\n");
\r
285 if (ReadDWord(file) != 0x00010000)
\r
288 WriteLogMsg("File was NOT a TTF file!\n");
\r
290 return false; // Not a TTF file...
\r
295 uint32 num_tabs = ReadWord(file); // Get # of tables
\r
297 WriteLogMsg("Number of tables is %u...\n", num_tabs);
\r
299 // fskip(file, 6); // Skip this shiat...
\r
300 fseek(file, 6, SEEK_CUR);
\r
303 WriteLogMsg("Reading names of tables...\n");
\r
305 for(uint32 i=0; i<num_tabs; i++)
\r
307 // ReadFile(file, names[i], 4, &bytesRead, NULL);
\r
308 fread(names[i], 1, 4, file);
\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
317 WriteLogMsg("Reading tables...\n");
\r
319 for(uint32 i=0; i<num_tabs; i++)
\r
321 for(uint32 j=0; j<NUMTABS; j++)
\r
323 if ((strcmp(names[i], narray[j])) == 0) // Found a match...
\r
325 // *parray[j] = (uint8 *)GlobalAlloc(GMEM_FIXED, length[i]); // Allocate space
\r
326 *parray[j] = (uint8 *)malloc(length[i]); // Alloc space
\r
328 if (*parray[j] == NULL)
\r
329 return false; // Bail out if nothing allocated
\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
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
352 /////////////////////////////////////////////////////////////////////////////
\r
353 // Member function: BOOL Save(const char * filename)
\r
355 // Save the TT font currently in the object
\r
356 /////////////////////////////////////////////////////////////////////////////
\r
357 bool TTF::Save(const char * filename)
\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
370 EncodeGlyph(currentGlyph);
\r
372 BuildTables(); // Ignore return value...
\r
374 for(uint32 i=0; i<NUMTABS; i++) // Figure out how many tables there are
\r
375 if ((*parray[i]) != NULL)
\r
378 uint32 offset = 12 + (numtabs * 16); // Calc correct offset to start of data
\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
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
390 for(uint32 i=0; i<NUMTABS; i++) // Write out table directory...
\r
392 if ((*parray[i]) != NULL)
\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
399 WriteDWord(file, 0); // Checksum
\r
400 WriteDWord(file, offset); // Offset
\r
401 WriteDWord(file, (*larray[i])); // Length
\r
403 offset += (((*larray[i]) + 3) & ~3); // Pad out to 4-uint8 boundary...
\r
407 for(uint32 i=0; i<NUMTABS; i++) // Write out the tables...
\r
409 if ((*parray[i]) != NULL)
\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
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
427 return true; // Whether or not it was successful...
\r
430 /////////////////////////////////////////////////////////////////////////////
\r
431 // Member function: BOOL EncodeGlyph(int glyphnum)
\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
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
441 if (glyphnum < myMaxp.numGlyphs) // numofgls is 1 based ind, glyph# 0 based
\r
443 // need to add composite encoding...
\r
444 int lastx = 0, lasty = 0;
\r
446 for(uint32 i=0; i<numberOfPoints; i++)
\r
449 int curx = gx[i] - lastx, cury = gy[i] - lasty;
\r
452 flag |= 0x01; // Set on curve info
\r
456 if ((curx > 255) || (curx < -255)) // I.e., it's 2 uint8 value
\r
457 SetWord(xbuf, xp, curx);
\r
462 flag |= 0x02; // I.e., it's negative
\r
463 curx *= -1; // Flip it so correct value is stored
\r
468 SetByte(xbuf, xp, curx); // Automagically strips neg bit
\r
472 flag |= 0x10; // X-coord is same...
\r
476 if ((cury > 255) || (cury < -255)) // I.e., it's 2 uint8 value
\r
477 SetWord(ybuf, yp, cury);
\r
482 flag |= 0x04; // I.e., it's negative
\r
488 SetByte(ybuf, yp, cury);
\r
492 flag |= 0x20; // Y-coord is same...
\r
495 lastx = gx[i]; lasty = gy[i];
\r
498 // Now crunch flags... ugly, ugly, ugly.
\r
500 fbuf[numberOfPoints] = 0; // Set sentinel value (ugly way to do this)
\r
501 for(i=0; i<numberOfPoints; i++);
\r
503 if (fbuf[i] == fbuf[i+1]) //
\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
508 fbuf[fp++] = fbuf[i] | 0x08; // Set repeat flag
\r
509 fbuf[fp++] = count; // & number of repeats
\r
511 else fbuf[fp++] = fbuf[i]; // Otherwise, just copy...
\r
514 fp = numberOfPoints;
\r
515 // Find length of glyph and reallocate space if necessary
\r
517 uint32 newLength = 12 + numberOfPolys*2 + numberOfHints + fp + xp + yp;
\r
519 if (newLength & 0x03)
\r
520 newLength += (4 - newLength & 0x03);
\r
522 if (glyphLen[glyphnum] != newLength)
\r
524 glyph[glyphnum] = (uint8 *)realloc(glyph[glyphnum], newLength);
\r
525 glyphLen[glyphnum] = newLength;
\r
528 // And finally, store it!
\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
548 retval = true; // Successfully encoded!
\r
554 /////////////////////////////////////////////////////////////////////////////
\r
555 // Member function: BOOL DecodeGlyph(int glyphnum)
\r
557 // This function decodes the glyph data and stores it to the object's
\r
559 /////////////////////////////////////////////////////////////////////////////
\r
560 bool TTF::DecodeGlyph(uint16 glyphnum)
\r
562 bool retval = false;
\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
569 if (!glyphLen[glyphnum])
\r
571 numberOfPoints = numberOfPolys = 0;
\r
572 return true; // Zero length IS valid...
\r
574 // else // Get character data...
\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
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
586 // Need to handle composite glyphs better here. The ways things
\r
587 // are set now is a recipe for disaster...
\r
589 if (numberOfPolys == 0xFFFF)
\r
591 isCompositeGlyph = true;
\r
592 numberOfPolys = 0; // Set for no points
\r
596 while (!compositeList.IsEmpty()) // Empty composite list...
\r
597 compositeList.GetFront();
\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
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
617 compositeList.AddAtRear(cmpst);
\r
619 while (cmpst.flags & 0x20); //*/
\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
631 // USHORT arg1and2; /* (arg1 << 8) | arg2 */
\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
644 //} while ( flags & MORE_COMPONENTS )
\r
645 //if (flags & WE_HAVE_INSTR){
\r
647 // uint8 instr[numInstr]
\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
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
671 for(i=0; i<numberOfPolys; i++)
\r
672 poly[i] = GetWord(glyph[glyphnum], dp);
\r
674 numberOfHints = GetWord(glyph[glyphnum], dp);
\r
676 for(i=0; i<numberOfHints; i++)
\r
677 hint[i] = GetByte(glyph[glyphnum], dp);
\r
679 // Decode the dots...
\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
685 int xx = 0, yy = 0, repeat;
\r
686 uint32 numTokens = num_pts, k, numRep;
\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
692 for(uint32 i=0; i<numTokens; i++)
\r
694 uint8 token = glyph[glyphnum][dp+i]; uint32 rpts = 1;
\r
696 if (token & 0x08) // Repeated token?
\r
698 i++; // Yes, bump pointer to # of times to repeat
\r
699 numRep = glyph[glyphnum][dp+i];
\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
709 // 10 = same x(0uint8s), 00 = 2uint8s, 02&12 = 1uint8
\r
710 if ((token & 0x02) == 0x02)
\r
713 if ((token & 0x12) == 0x00)
\r
717 xptr = dp + numTokens;
\r
718 yptr = dp + numTokens + numXs;
\r
720 // & continue decoding X/Y-coords...
\r
722 k = 0; // Index to the point array
\r
724 for(uint32 i=0; i<numTokens; i++)
\r
726 uint8 token = glyph[glyphnum][dp+i];
\r
732 repeat += glyph[glyphnum][dp+i]; // Set repeat data...
\r
737 if ((token & 0x12) == 0x12)
\r
738 xx += GetByte(glyph[glyphnum], xptr);
\r
740 if ((token & 0x12) == 0x02)
\r
741 xx -= GetByte(glyph[glyphnum], xptr);
\r
743 if ((token & 0x12) == 0x00)
\r
744 xx += (int16)GetWord(glyph[glyphnum], xptr);
\r
746 gx[k] = xx; // Store x-coordinate
\r
748 if ((token & 0x24) == 0x24)
\r
749 yy += GetByte(glyph[glyphnum], yptr);
\r
751 if ((token & 0x24) == 0x04)
\r
752 yy -= GetByte(glyph[glyphnum], yptr);
\r
754 if ((token & 0x24) == 0x00)
\r
755 yy += (int16)GetWord(glyph[glyphnum], yptr);
\r
757 gy[k] = yy; // Store y-coordinate
\r
759 onCurve[k++] = (token & 0x01 ? true : false); // If bit 0 set, then it's on curve
\r
763 retval = true; // Hmm. Successfully decoded a glyph...
\r
766 isDirty = false; // do it here?
\r
771 /*****************************************************************************
\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
779 if (DecodeGlyph(glyphNum))
\r
780 return GlyphPoints(numberOfPoints, numberOfPolys, gx, gy, onCurve, poly);
\r
782 return GlyphPoints();
\r
785 /*****************************************************************************
\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
793 // int tmpGlyph = currentGlyph;
\r
795 DecodeGlyph(glyphNum); // Check for composite-ness
\r
797 if (!isCompositeGlyph)
\r
798 return GlyphPoints();
\r
801 for(int i=1; i<=pDoc->m_myFont.compositeList.Length(); i++)
\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
809 fnt->SetGlyph(pDoc->character_num);
\r
812 GlyphPoints retVal;
\r
814 for(int i=1; i<=compositeList.Length(); i++)
\r
816 Composite cmpst = compositeList.PeekPosition(i);
\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
824 if (cmpst.flags & 0x0002)
\r
825 gp.OffsetPoints(cmpst.arg1, cmpst.arg2);
\r
827 retVal = retVal + gp;
\r
828 // NOTE: May have to adjust scanlines as per 0x0002 above...
\r
831 // SetGlyph(tmpGlyph);
\r
832 DecodeGlyph(currentGlyph); // Reset needed here...
\r
837 /////////////////////////////////////////////////////////////////////////////
\r
838 // Member function: void GetCharName(int cNum, uint8 * buf)
\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
844 buf[0] = 0; // Set failure as default condition
\r
846 if (!post) // PS names are here...
\r
849 if (post[1] != 0x02 || post[2] != 0x00) // i.e., it's NOT a V2.0 table
\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
860 nInd2 = tabOff + (2 * numGlyphs);
\r
866 pTab = macStdNames;
\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
872 uint8 len = pTab[nInd2];
\r
875 for(uint8 i=0; i<len; i++)
\r
876 buf[i] = pTab[nInd2 + i];
\r
881 /////////////////////////////////////////////////////////////////////////////
\r
882 // Member function: BOOL ExtractTables(void)
\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
889 if (head_len != 54)
\r
892 WriteLogMsg("Bad HEAD header: Expected 54, found %u...\n", head_len);
\r
894 return false; // Corrupt data?
\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
918 if (maxp_len != 32)
\r
921 WriteLogMsg("Bad MAXP header: Expected 32, found %u...\n", maxp_len);
\r
923 return false; // Corrupt data?
\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
943 tp = 0; // Reset table pointer
\r
944 uint32 start = (myHead.indexToLocFormat ? GetDWord(loca, tp) : GetWord(loca, tp) << 1);
\r
946 for(uint32 i=0; i<myMaxp.numGlyphs; i++)
\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
952 if (length) // loca+start? pointer arithmetic?
\r
954 glyph[i] = (uint8 *)malloc(length); // Allocate space,
\r
955 memcpy(glyph[i], glyf+start, length); // and move it!
\r
960 start = end; // Reset start value
\r
966 /////////////////////////////////////////////////////////////////////////////
\r
967 // Member function: BOOL BuildTables(void)
\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
974 uint32 i, tp, start;
\r
976 myHead.indexToLocFormat = 1; // We don't bother with [uint16s*2] format...
\r
978 // Build HEAD table
\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
1001 // Build MAXP table
\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
1020 // Build LOCA & GLYF tables
\r
1022 loca_len = (myMaxp.numGlyphs+1) * 4; // Set size of table
\r
1025 free(loca); // And create/reallocate it...
\r
1027 loca = (uint8 *) malloc(loca_len);
\r
1029 glyf_len = 0; // Refigure glyf table length
\r
1031 for(i=0; i<myMaxp.numGlyphs; i++)
\r
1032 glyf_len += glyphLen[i];
\r
1037 glyf = (uint8 *) malloc(glyf_len);
\r
1039 start = tp = 0; // Reset table pointer
\r
1041 for(i=0; i<myMaxp.numGlyphs; i++)
\r
1043 SetDWord(loca, tp, start); // Store glyph start address
\r
1046 memcpy(glyf+start, glyph[i], glyphLen[i]);
\r
1048 start += glyphLen[i];
\r
1051 SetDWord(loca, tp, start); // Finally, store end of glyphs+1
\r
1056 /////////////////////////////////////////////////////////////////////////////
\r
1057 // Member function: BOOL SetGlyph(int glyphnum)
\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
1065 bool retval = false; // Set failure as default
\r
1068 EncodeGlyph(currentGlyph);
\r
1072 if (glyphnum < myMaxp.numGlyphs) // numofgls is 1 based ind, glyph# 0 based
\r
1074 currentGlyph = glyphnum;
\r
1075 DecodeGlyph(currentGlyph);
\r
1082 /////////////////////////////////////////////////////////////////////////////
\r
1083 // Member function: BOOL AddGlyph(int glyphnum)
\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
1091 // incomplete: JLH
\r
1092 bool retval = false;
\r
1095 EncodeGlyph(currentGlyph);
\r
1102 /////////////////////////////////////////////////////////////////////////////
\r
1103 // Member function: BOOL DeleteGlyph(int glyphnum)
\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
1110 // incomplete: JLH
\r
1111 bool retval = false;
\r
1117 // Various & sundry member functions implementation
\r
1119 // NOTE: For error handling, should throw exceptions--not return values...! !!! FIX !!!
\r
1122 Box TTF::GetBoundingBox(void)
\r
1124 return Box(llx, lly, urx, ury);
\r
1127 GlyphPt TTF::GetPoint(uint16 pointno)
\r
1131 if (pointno >= MAXPOINTS)
\r
1132 return p; // Fix to make invalid
\r
1134 p.x = gx[pointno], p.y = gy[pointno], p.onCurve = onCurve[pointno];
\r
1138 uint16 TTF::GetNumberOfPolys(void)
\r
1140 return numberOfPolys;
\r
1143 uint16 TTF::GetPolyEnd(uint16 polynum)
\r
1145 if (polynum >= numberOfPolys)
\r
1148 return poly[polynum];
\r
1151 int TTF::GetPointX(uint16 pointno)
\r
1153 if (pointno >= MAXPOINTS)
\r
1156 return gx[pointno];
\r
1159 int TTF::GetPointY(uint16 pointno)
\r
1161 if (pointno >= MAXPOINTS)
\r
1164 return gy[pointno];
\r
1167 bool TTF::GetOnCurve(uint16 pointno)
\r
1169 if (pointno >= MAXPOINTS)
\r
1172 return onCurve[pointno];
\r
1175 bool TTF::SetOnCurve(uint16 pointno, bool state)
\r
1177 if (pointno >= numberOfPoints)
\r
1180 onCurve[pointno] = state;
\r
1186 bool TTF::MovePoint(uint16 pointno, int x, int y)
\r
1188 if (pointno >= numberOfPoints)
\r
1191 gx[pointno] = x; gy[pointno] = y;
\r
1197 bool TTF::MovePoint(uint16 pointno, GlyphPt p)
\r
1199 if (pointno >= numberOfPoints)
\r
1202 gx[pointno] = p.x; gy[pointno] = p.y; onCurve[pointno] = p.onCurve;
\r
1208 bool TTF::IsCompositeGlyph(void)
\r
1210 return isCompositeGlyph;
\r