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