1 //******************************************************************************
2 ///
3 /// @file core/shape/truetype.cpp
4 ///
5 /// Implementation of the TrueType-based text geometric primitive.
6 ///
7 /// @author Alexander Enzmann
8 ///
9 /// @copyright
10 /// @parblock
11 ///
12 /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
13 /// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd.
14 ///
15 /// POV-Ray is free software: you can redistribute it and/or modify
16 /// it under the terms of the GNU Affero General Public License as
17 /// published by the Free Software Foundation, either version 3 of the
18 /// License, or (at your option) any later version.
19 ///
20 /// POV-Ray is distributed in the hope that it will be useful,
21 /// but WITHOUT ANY WARRANTY; without even the implied warranty of
22 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 /// GNU Affero General Public License for more details.
24 ///
25 /// You should have received a copy of the GNU Affero General Public License
26 /// along with this program.  If not, see <http://www.gnu.org/licenses/>.
27 ///
28 /// ----------------------------------------------------------------------------
29 ///
30 /// POV-Ray is based on the popular DKB raytracer version 2.12.
31 /// DKBTrace was originally written by David K. Buck.
32 /// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
33 ///
34 /// @endparblock
35 ///
36 //******************************************************************************
37 
38 // Unit header file must be the first file included within POV-Ray *.cpp files (pulls in config)
39 #include "core/shape/truetype.h"
40 
41 #include <map>
42 
43 #include "base/fileinputoutput.h"
44 
45 #include "core/bounding/boundingbox.h"
46 #include "core/math/matrix.h"
47 #include "core/render/ray.h"
48 #include "core/scene/tracethreaddata.h"
49 #include "core/shape/csg.h"
50 
51 // this must be the last file included
52 #include "base/povdebug.h"
53 
54 namespace pov
55 {
56 
57 /*****************************************************************************
58 * Local preprocessor defines
59 ******************************************************************************/
60 
61 /* uncomment this to debug ttf. DEBUG1 gives less output than DEBUG2
62 #define TTF_DEBUG2 1
63 #define TTF_DEBUG 1
64 #define TTF_DEBUG3 1
65 */
66 
67 const DBL TTF_Tolerance = 1.0e-6;    /* -4 worked, -8 failed */
68 
69 const int MAX_ITERATIONS = 50;
70 const DBL COEFF_LIMIT = 1.0e-20;
71 
72 /* For decoding glyph coordinate bit flags */
73 const int ONCURVE            = 0x01;
74 const int XSHORT             = 0x02;
75 const int YSHORT             = 0x04;
76 const int REPEAT_FLAGS       = 0x08;  /* repeat flag n times */
77 const int SHORT_X_IS_POS     = 0x10;  /* the short vector is positive */
78 const int NEXT_X_IS_ZERO     = 0x10;  /* the relative x coordinate is zero */
79 const int SHORT_Y_IS_POS     = 0x20;  /* the short vector is positive */
80 const int NEXT_Y_IS_ZERO     = 0x20;  /* the relative y coordinate is zero */
81 
82 /* For decoding multi-component glyph bit flags */
83 const int ARG_1_AND_2_ARE_WORDS    = 0x0001;
84 const int ARGS_ARE_XY_VALUES       = 0x0002;
85 const int ROUND_XY_TO_GRID         = 0x0004;
86 const int WE_HAVE_A_SCALE          = 0x0008;
87 /*      RESERVED                 = 0x0010 */
88 const int MORE_COMPONENTS          = 0x0020;
89 const int WE_HAVE_AN_X_AND_Y_SCALE = 0x0040;
90 const int WE_HAVE_A_TWO_BY_TWO     = 0x0080;
91 const int WE_HAVE_INSTRUCTIONS     = 0x0100;
92 const int USE_MY_METRICS           = 0x0200;
93 
94 /* For decoding kern coverage bit flags */
95 const int KERN_HORIZONTAL    = 0x01;
96 const int KERN_MINIMUM       = 0x02;
97 const int KERN_CROSS_STREAM  = 0x04;
98 const int KERN_OVERRIDE      = 0x08;
99 
100 /* Some marcos to make error detection easier, as well as clarify code */
101 #define READSHORT(fp) readSHORT(fp, __LINE__, __FILE__)
102 #define READLONG(fp) readLONG(fp, __LINE__, __FILE__)
103 #define READUSHORT(fp) readUSHORT(fp, __LINE__, __FILE__)
104 #define READULONG(fp) readULONG(fp, __LINE__, __FILE__)
105 #define READFIXED(fp) readLONG(fp, __LINE__, __FILE__)
106 #define READFWORD(fp) readSHORT(fp, __LINE__, __FILE__)
107 #define READUFWORD(fp) readUSHORT(fp, __LINE__, __FILE__)
108 
109 /*****************************************************************************
110 * Local typedefs
111 ******************************************************************************/
112 
113 /* Type definitions to match the TTF spec, makes code clearer */
114 typedef POV_UINT8   BYTE;
115 typedef POV_INT16   SHORT;
116 typedef POV_UINT16  USHORT;
117 typedef POV_INT32   LONG;
118 typedef POV_UINT32  ULONG;
119 typedef POV_INT16   FWord;
120 typedef POV_UINT16  uFWord;
121 
122 #if !defined(TARGET_OS_MAC)
123 typedef int Fixed;
124 #endif
125 
126 typedef struct
127 {
128     Fixed version;                /* 0x10000 (1.0) */
129     USHORT numTables;             /* number of tables */
130     USHORT searchRange;           /* (max2 <= numTables)*16 */
131     USHORT entrySelector;         /* log2 (max2 <= numTables) */
132     USHORT rangeShift;            /* numTables*16-searchRange */
133 } sfnt_OffsetTable;
134 
135 typedef struct
136 {
137     BYTE tag[4];
138     ULONG checkSum;
139     ULONG offset;
140     ULONG length;
141 } sfnt_TableDirectory;
142 
143 typedef sfnt_TableDirectory *sfnt_TableDirectoryPtr;
144 
145 typedef struct
146 {
147     ULONG bc;
148     ULONG ad;
149 } longDateTime;
150 
151 typedef struct
152 {
153     Fixed version;                /* for this table, set to 1.0 */
154     Fixed fontRevision;           /* For Font Manufacturer */
155     ULONG checkSumAdjustment;
156     ULONG magicNumber;            /* signature, must be 0x5F0F3CF5 == MAGIC */
157     USHORT flags;
158     USHORT unitsPerEm;            /* How many in Font Units per EM */
159 
160     longDateTime created;
161     longDateTime modified;
162 
163     FWord xMin;                   /* Font wide bounding box in ideal space */
164     FWord yMin;                   /* Baselines and metrics are NOT worked */
165     FWord xMax;                   /* into these numbers) */
166     FWord yMax;
167 
168     USHORT macStyle;              /* macintosh style word */
169     USHORT lowestRecPPEM;         /* lowest recommended pixels per Em */
170 
171     SHORT fontDirectionHint;
172     SHORT indexToLocFormat;       /* 0 - short offsets, 1 - long offsets */
173     SHORT glyphDataFormat;
174 } sfnt_FontHeader;
175 
176 typedef struct
177 {
178     USHORT platformID;
179     USHORT specificID;
180     ULONG offset;
181 } sfnt_platformEntry;
182 
183 typedef sfnt_platformEntry *sfnt_platformEntryPtr;
184 
185 typedef struct
186 {
187     USHORT format;
188     USHORT length;
189     USHORT version;
190 } sfnt_mappingTable;
191 
192 typedef struct
193 {
194     Fixed version;
195 
196     FWord Ascender;
197     FWord Descender;
198     FWord LineGap;
199 
200     uFWord advanceWidthMax;
201     FWord minLeftSideBearing;
202     FWord minRightSideBearing;
203     FWord xMaxExtent;
204     SHORT caretSlopeRise;
205     SHORT caretSlopeRun;
206 
207     SHORT reserved1;
208     SHORT reserved2;
209     SHORT reserved3;
210     SHORT reserved4;
211     SHORT reserved5;
212 
213     SHORT metricDataFormat;
214     USHORT numberOfHMetrics;      /* number of hMetrics in the hmtx table */
215 } sfnt_HorizHeader;
216 
217 struct GlyphHeader
218 {
219     SHORT numContours;
220     SHORT xMin;
221     SHORT yMin;
222     SHORT xMax;
223     SHORT yMax;
GlyphHeaderpov::GlyphHeader224     GlyphHeader() : numContours(0), xMin(0), yMin(0), xMax(0), yMax(0) {}
225 };
226 
227 struct GlyphOutline
228 {
229     GlyphHeader header;
230     std::vector<USHORT> endPoints;
231     std::vector<BYTE>   flags;
232     std::vector<DBL>    x, y;
233     USHORT myMetrics;
234 
GlyphOutlinepov::GlyphOutline235     GlyphOutline() :
236         myMetrics(0)
237     {}
238 };
239 
240 typedef struct
241 {
242     BYTE inside_flag;             /* 1 if this an inside contour, 0 if outside */
243     USHORT count;                 /* Number of points in the contour */
244     vector<BYTE> flags;           /* On/off curve flags */
245     vector<DBL> x, y;             /* Coordinates of control vertices */
246 } Contour;
247 
248 
249 /* Contour information for a single glyph */
250 struct GlyphStruct
251 {
252     GlyphHeader header;           /* Count and sizing information about this
253                                    * glyph */
254     USHORT glyph_index;           /* Internal glyph index for this character */
255     Contour *contours;            /* Array of outline contours */
256     USHORT unitsPerEm;            /* Max units character */
257     USHORT myMetrics;             /* Which glyph index this is for metrics */
258 };
259 
260 typedef struct KernData_struct
261 {
262     USHORT left, right;           /* Glyph index of left/right to kern */
263     FWord value;                  /* Delta in FUnits to apply in between */
264 } KernData;
265 
266 /*
267  * [esp] There's already a "KernTable" on the Mac... renamed to TTKernTable for
268  * now in memorium to its author.
269  */
270 
271 typedef struct KernStruct
272 {
273     USHORT coverage;              /* Coverage bit field of this subtable */
274     USHORT nPairs;                /* # of kerning pairs in this table */
275     KernData *kern_pairs;         /* Array of kerning values */
276 } TTKernTable;
277 
278 typedef struct KernTableStruct
279 {
280     USHORT nTables;               /* # of subtables in the kerning table */
281     TTKernTable *tables;
282 } KernTables;
283 
284 typedef struct longHorMertric
285 {
286     uFWord advanceWidth;          /* Total width of a glyph in FUnits */
287     FWord lsb;                    /* FUnits to the left of the glyph */
288 } longHorMetric;
289 
290 
291 typedef std::map<USHORT, GlyphPtr> GlyphPtrMap;
292 
293 struct TrueTypeInfo
294 {
295     TrueTypeInfo();
296     ~TrueTypeInfo();
297 
298     USHORT platformID[4];             /* Character encoding search order */
299     USHORT specificID[4];
300     ULONG cmap_table_offset;          /* File locations for these tables */
301     ULONG glyf_table_offset;
302     USHORT numGlyphs;                 /* How many symbols in this file */
303     USHORT unitsPerEm;                /* The "resoultion" of this font */
304     SHORT indexToLocFormat;           /* 0 - short format, 1 - long format */
305     ULONG *loca_table;                /* Mapping from characters to glyphs */
306     GlyphPtrMap glyphsByChar;         /* Cached info for this font */
307     GlyphPtrMap glyphsByIndex;        /* Cached info for this font */
308     KernTables kerning_tables;        /* Kerning info for this font */
309     USHORT numberOfHMetrics;          /* The number of explicit spacings */
310     longHorMetric *hmtx_table;        /* Horizontal spacing info */
311     ULONG glyphIDoffset;              /* Offset for Type 4 encoding tables */
312     USHORT segCount, searchRange,     /* Counts for Type 4 encoding tables */
313            entrySelector, rangeShift;
314     USHORT *startCount, *endCount,    /* Type 4 (MS) encoding tables */
315            *idDelta, *idRangeOffset;
316 };
317 
318 /*****************************************************************************
319 * Local variables
320 ******************************************************************************/
321 
322 const BYTE tag_CharToIndexMap[] = "cmap"; /* 0x636d6170; */
323 const BYTE tag_FontHeader[]     = "head"; /* 0x68656164; */
324 const BYTE tag_GlyphData[]      = "glyf"; /* 0x676c7966; */
325 const BYTE tag_IndexToLoc[]     = "loca"; /* 0x6c6f6361; */
326 const BYTE tag_Kerning[]        = "kern"; /* 0x6b65726e; */
327 const BYTE tag_MaxProfile[]     = "maxp"; /* 0x6d617870; */
328 const BYTE tag_HorizHeader[]    = "hhea"; /* 0x68686561; */
329 const BYTE tag_HorizMetric[]    = "hmtx"; /* 0x686d7478; */
330 const BYTE tag_TTCFontFile[]    = "ttcf"; /* */
331 
332 /*****************************************************************************
333 * Static functions
334 ******************************************************************************/
335 
336 /* Byte order independent I/O routines (probably already in other routines) */
337 SHORT readSHORT(IStream *infile, int line, const char *file);
338 USHORT readUSHORT(IStream *infile, int line, const char *file);
339 LONG readLONG(IStream *infile, int line, const char *file);
340 ULONG readULONG(IStream *infile, int line, const char *file);
341 int compare_tag4(BYTE *ttf_tag, BYTE *known_tag);
342 
343 /* Internal TTF input routines */
344 void ProcessFontFile(TrueTypeFont* ffile);
345 void ProcessHeadTable(TrueTypeFont *ffile, int head_table_offset);
346 void ProcessLocaTable(TrueTypeFont *ffile, int loca_table_offset);
347 void ProcessMaxpTable(TrueTypeFont *ffile, int maxp_table_offset);
348 void ProcessKernTable(TrueTypeFont *ffile, int kern_table_offset);
349 void ProcessHheaTable(TrueTypeFont *ffile, int hhea_table_offset);
350 void ProcessHmtxTable(TrueTypeFont *ffile, int hmtx_table_offset);
351 GlyphPtr ProcessCharacter(TrueTypeFont *ffile, unsigned int search_char, unsigned int *glyph_index);
352 USHORT ProcessCharMap(TrueTypeFont *ffile, unsigned int search_char);
353 USHORT ProcessFormat0Glyph(TrueTypeFont *ffile, unsigned int search_char);
354 USHORT ProcessFormat4Glyph(TrueTypeFont *ffile, unsigned int search_char);
355 USHORT ProcessFormat6Glyph(TrueTypeFont *ffile, unsigned int search_char);
356 GlyphPtr ExtractGlyphInfo(TrueTypeFont *ffile, unsigned int glyph_index, unsigned int c);
357 GlyphOutline *ExtractGlyphOutline(TrueTypeFont *ffile, unsigned int glyph_index, unsigned int c);
358 GlyphPtr ConvertOutlineToGlyph(TrueTypeFont *ffile, const GlyphOutline *ttglyph);
359 
readSHORT(IStream * infile,int line,const char * file)360 SHORT readSHORT(IStream *infile, int line, const char *file)
361 {
362     // On platforms using non-2's-complement representation for negative numbers, any approach
363     // starting with a signed interpretation of the data is doomed to fail over those
364     // representations' property of having two representations for zero, and none for -2^(N-1).
365     // We therefore must start off with an unsigned representation of the data.
366     USHORT u = readUSHORT(infile, line, file);
367 
368     // We go on by testing for a set signed bit, which in 2's complement format indicates that
369     // the actual value we're looking for is the unsigned interpretation minus 2^N.
370     if (u & INTEGER16_SIGN_MASK)
371         // To compute that value, we first discard the sign bit (which is equivalent to subtracting
372         // 2^(N-1)), then add -2^(N-1). Finally we cram the result into the target type.
373         return (SHORT(u ^ INTEGER16_SIGN_MASK)) + SIGNED16_MIN;
374     else
375         return SHORT(u);
376 }
377 
readUSHORT(IStream * infile,int line,const char * file)378 USHORT readUSHORT(IStream *infile, int line, const char *file)
379 {
380     int i0, i1 = 0; /* To quiet warnings */
381 
382     if ((i0  = infile->Read_Byte ()) == EOF || (i1  = infile->Read_Byte ()) == EOF)
383     {
384         throw pov_base::Exception(__FUNCTION__, file, line, kFileDataErr, "Cannot read TrueType font file.");
385     }
386 
387     return (USHORT)((((USHORT)i0) << 8) | ((USHORT)i1));
388 }
389 
readLONG(IStream * infile,int line,const char * file)390 LONG readLONG(IStream *infile, int line, const char *file)
391 {
392     // On platforms using non-2's-complement representation for negative numbers, any approach
393     // starting with a signed interpretation of the data is doomed to fail over those
394     // representations' property of having two representations for zero, and none for -2^(N-1).
395     // We therefore must start off with an unsigned representation of the data.
396     ULONG u = readULONG(infile, line, file);
397 
398     // We go on by testing for a set signed bit, which in 2's complement format indicates that
399     // the actual value we're looking for is the unsigned interpretation minus 2^N.
400     if (u & INTEGER32_SIGN_MASK)
401         // To compute that value, we first discard the sign bit (which is equivalent to subtracting
402         // 2^(N-1)), then add -2^(N-1). Finally we cram the result into the target type.
403         return (LONG(u ^ INTEGER32_SIGN_MASK)) + SIGNED32_MIN;
404     else
405         return LONG(u);
406 }
407 
readULONG(IStream * infile,int line,const char * file)408 ULONG readULONG(IStream *infile, int line, const char *file)
409 {
410     int i0, i1 = 0, i2 = 0, i3 = 0;  /* To quiet warnings */
411 
412     if ((i0 = infile->Read_Byte ()) == EOF || (i1 = infile->Read_Byte ()) == EOF ||
413         (i2 = infile->Read_Byte ()) == EOF || (i3 = infile->Read_Byte ()) == EOF)
414     {
415         throw pov_base::Exception(__FUNCTION__, file, line, kFileDataErr, "Cannot read TrueType font file.");
416     }
417 
418     return (ULONG) ((((ULONG) i0) << 24) | (((ULONG) i1) << 16) |
419                     (((ULONG) i2) << 8)  |  ((ULONG) i3));
420 }
421 
compare_tag4(const BYTE * ttf_tag,const BYTE * known_tag)422 static int compare_tag4(const BYTE *ttf_tag, const BYTE *known_tag)
423 {
424     return (ttf_tag[0] == known_tag[0] && ttf_tag[1] == known_tag[1] &&
425             ttf_tag[2] == known_tag[2] && ttf_tag[3] == known_tag[3]);
426 }
427 
428 /*****************************************************************************
429 *
430 * FUNCTION
431 *
432 *   ProcessNewTTF
433 *
434 * INPUT
435 *
436 * OUTPUT
437 *
438 * RETURNS
439 *
440 * AUTHOR
441 *
442 *   Alexander Ennzmann
443 *
444 * DESCRIPTION
445 *
446 *   Takes an input string and a font filename, and creates a POV-Ray CSG
447 *   object for each letter in the string.
448 *
449 * CHANGES
450 *
451 *   Allow usage of built-in fonts via an additional parameter
452 *   (triggered when filename is null) - Oct 2012 [JG]
453 *
454 ******************************************************************************/
ProcessNewTTF(CSG * Object,TrueTypeFont * ffile,const UCS2 * text_string,DBL depth,const Vector3d & offset)455 void TrueType::ProcessNewTTF(CSG *Object, TrueTypeFont *ffile, const UCS2 *text_string, DBL depth, const Vector3d& offset)
456 {
457     Vector3d local_offset, total_offset;
458     TrueType *ttf;
459     DBL funit_size;
460     TTKernTable *table;
461     USHORT coverage;
462     unsigned int search_char;
463     unsigned int glyph_index, last_index = 0;
464     FWord kern_value_x, kern_value_min_x;
465     FWord kern_value_y, kern_value_min_y;
466     int i, j, k;
467     TRANSFORM Trans;
468 
469     /* Get info about each character in the string */
470     total_offset = Vector3d(0.0, 0.0, 0.0);
471 
472     for (i = 0; text_string[i] != 0; i++)
473     {
474         /*
475          * We need to make sure (for now) that this is only the lower 8 bits,
476          * so we don't have all the high bits set if converted from a signed
477          * char to an unsigned short.
478          */
479         search_char = (unsigned int)(text_string[i]);
480 
481 #ifdef TTF_DEBUG
482         Debug_Info("\nChar: '%c' (0x%X), Offset[%d]: <%g,%g,%g>\n", (char)search_char,
483             search_char, i, total_offset[X], total_offset[Y], total_offset[Z]);
484 #endif
485 
486         /* Make a new child for each character */
487         ttf = new TrueType();
488 
489         /* Set the depth information for the character */
490         ttf->depth = depth;
491 
492         /*
493          * Get pointers to the contour information for each character
494          * in the text string.
495          */
496         ttf->glyph = ProcessCharacter(ffile, search_char, &glyph_index);
497         funit_size = 1.0 / (DBL)(ffile->info->unitsPerEm);
498 
499         /*
500          * Spacing based on the horizontal metric table, the kerning table,
501          * and (possibly) the previous glyph.
502          */
503         if (i == 0) /* Ignore spacing on the left for the first character only */
504         {
505             /* Shift the glyph to start at the origin */
506             total_offset[X] = -ttf->glyph->header.xMin * funit_size;
507 
508             Compute_Translation_Transform(&Trans, total_offset);
509 
510             ttf->Translate(total_offset, &Trans);
511 
512             /* Shift next glyph by the width of this one excluding the left offset*/
513             total_offset[X] = (ffile->info->hmtx_table[ttf->glyph->myMetrics].advanceWidth -
514                                ffile->info->hmtx_table[ttf->glyph->myMetrics].lsb) * funit_size;
515 
516 #ifdef TTF_DEBUG
517             Debug_Info("aw(%d): %g\n", i,
518                                (ffile->info->hmtx_table[ttf->glyph->myMetrics].advanceWidth -
519                                 ffile->info->hmtx_table[ttf->glyph->myMetrics].lsb)*funit_size);
520 #endif
521         }
522         else /* Kern all of the other characters */
523         {
524             kern_value_x = kern_value_y = 0;
525             kern_value_min_x = kern_value_min_y = -ffile->info->unitsPerEm;
526             local_offset = Vector3d(0.0, 0.0, 0.0);
527 
528             for (j = 0; j < ffile->info->kerning_tables.nTables; j++)
529             {
530                 table = ffile->info->kerning_tables.tables;
531                 coverage = table->coverage;
532 
533                 /*
534                  * Don't use vertical kerning until such a time when we support
535                  * characters moving in the vertical direction...
536                  */
537                 if (!(coverage & KERN_HORIZONTAL))
538                     continue;
539 
540                 /*
541                  * If we were keen, we could do a binary search for this
542                  * character combination, since the pairs are sorted in
543                  * order as if the left and right index values were a 32 bit
544                  * unsigned int (mostly - at least they are sorted on the
545                  * left glyph).  Something to do when everything else works...
546                  */
547                 for (k = 0; k < table[j].nPairs; k++)
548                 {
549                     if (table[j].kern_pairs[k].left == last_index &&
550                         table[j].kern_pairs[k].right == ttf->glyph->myMetrics)
551                     {
552 #ifdef TTF_DEBUG2
553                         Debug_Info("Found a kerning for <%d, %d> = %d\n",
554                                    last_index, glyph_index, table[j].kern_pairs[k].value);
555 #endif
556 
557                         /*
558                          * By default, Windows & OS/2 assume at most a single table with
559                          * !KERN_MINIMUM, !KERN_CROSS_STREAM, KERN_OVERRIDE.
560                          */
561                         if (coverage & KERN_MINIMUM)
562                         {
563 #ifdef TTF_DEBUG2
564                             Debug_Info(" KERN_MINIMUM\n");
565 #endif
566                             if (coverage & KERN_CROSS_STREAM)
567                                 kern_value_min_y = table[j].kern_pairs[k].value;
568                             else
569                                 kern_value_min_x = table[j].kern_pairs[k].value;
570                         }
571                         else
572                         {
573                             if (coverage & KERN_CROSS_STREAM)
574                             {
575 #ifdef TTF_DEBUG2
576                                 Debug_Info(" KERN_CROSS_STREAM\n");
577 #endif
578                                 if (table[j].kern_pairs[k].value == (FWord)0x8000)
579                                 {
580                                     kern_value_y = 0;
581                                 }
582                                 else
583                                 {
584                                     if (coverage & KERN_OVERRIDE)
585                                         kern_value_y = table[j].kern_pairs[k].value;
586                                     else
587                                         kern_value_y += table[j].kern_pairs[k].value;
588                                 }
589                             }
590                             else
591                             {
592 #ifdef TTF_DEBUG2
593                                 Debug_Info(" KERN_VALUE\n");
594 #endif
595                                 if (coverage & KERN_OVERRIDE)
596                                     kern_value_x = table[j].kern_pairs[k].value;
597                                 else
598                                     kern_value_x += table[j].kern_pairs[k].value;
599                             }
600                         }
601                         break;
602                     }
603                     /* Abort now if we have passed all potential matches */
604                     else if (table[j].kern_pairs[k].left > last_index)
605                     {
606                         break;
607                     }
608                 }
609             }
610             kern_value_x = (kern_value_x > kern_value_min_x ?
611                             kern_value_x : kern_value_min_x);
612             kern_value_y = (kern_value_y > kern_value_min_y ?
613                             kern_value_y : kern_value_min_y);
614 
615             /*
616              * Offset this character so that the left edge of the glyph is at
617              * the previous offset + the lsb + any kerning amount.
618              */
619             local_offset[X] = total_offset[X] +
620                               (DBL)(ffile->info->hmtx_table[ttf->glyph->myMetrics].lsb -
621                                     ttf->glyph->header.xMin + kern_value_x) * funit_size;
622             local_offset[Y] = total_offset[Y] + (DBL)kern_value_y * funit_size;
623 
624             /* Translate this glyph to its final position in the string */
625             Compute_Translation_Transform(&Trans, local_offset);
626 
627             ttf->Translate(local_offset, &Trans);
628 
629             /* Shift next glyph by the width of this one + any kerning amount */
630             total_offset[X] += (ffile->info->hmtx_table[ttf->glyph->myMetrics].advanceWidth +kern_value_x) * funit_size;
631 
632 #ifdef TTF_DEBUG
633             Debug_Info("kern(%d): <%d, %d> (%g,%g)\n", i, last_index, glyph_index,
634                        (DBL)kern_value_x*funit_size, (DBL)kern_value_y * funit_size);
635             Debug_Info("lsb(%d): %g\n", i,
636                        (DBL)ffile->info->hmtx_table[glyph->myMetrics].lsb * funit_size);
637             Debug_Info("aw(%d): %g\n", i,
638                        (DBL)ffile->info->hmtx_table[glyph->myMetrics].advanceWidth *
639                        funit_size);
640 #endif
641         }
642 
643         /*
644          * Add to the offset of the next character the minimum spacing specified.
645          */
646         total_offset += offset;
647 
648         /* Link this glyph with the others in the union */
649         Object->Type |= (ttf->Type & CHILDREN_FLAGS);
650         ttf->Type |= IS_CHILD_OBJECT;
651         Object->children.push_back(ttf);
652 
653         last_index = glyph_index;
654     }
655 
656 #ifdef TTF_DEBUG
657     // TODO - text_string is an UCS2 strings, while Debug_Info will expect char strings.
658     #error "broken code"
659     if (!filename.empty())
660     {
661         Debug_Info("TTF parsing of \"%s\" from %s complete\n", text_string, filename.c_str());
662     }
663     else
664     {
665         Debug_Info("TTF parsing of \"%s\" from builtin %d complete\n", text_string, font_id);
666     }
667 #endif
668 
669     /* Close the font file descriptor */
670     if (ffile->fp != nullptr)
671     {
672         delete ffile->fp;
673         ffile->fp = nullptr;
674     }
675 }
676 
677 /*****************************************************************************
678 *
679 * FUNCTION
680 *
681 *   ProcessFontFile
682 *
683 * INPUT
684 *
685 * OUTPUT
686 *
687 * RETURNS
688 *
689 * AUTHOR
690 *
691 *   Alexander Ennzmann
692 *
693 * DESCRIPTION
694 *
695 * Read the header information about the specific font.  Parse the tables
696 * as we come across them.
697 *
698 * CHANGES
699 *
700 *   Added tests for reading manditory tables/validity checks - Jan 1996 [AED]
701 *   Reordered table parsing to avoid lots of file seeking - Jan 1996 [AED]
702 *
703 *   Added builtin fonts when fontfilename is nullptr - Oct 2012 [JG]
704 *
705 ******************************************************************************/
ProcessFontFile(TrueTypeFont * ffile)706 void ProcessFontFile(TrueTypeFont* ffile)
707 {
708     unsigned i;
709     int head_table_offset = 0;
710     int loca_table_offset = 0;
711     int maxp_table_offset = 0;
712     int kern_table_offset = 0;
713     int hhea_table_offset = 0;
714     int hmtx_table_offset = 0;
715     BYTE temp_tag[4];
716     sfnt_OffsetTable OffsetTable;
717     sfnt_TableDirectory Table;
718 
719     /* We have already read all the header info, no need to do it again */
720 
721     if (ffile->info != nullptr)
722         return;
723 
724     ffile->info = new TrueTypeInfo;
725 
726     /*
727         * For Microsoft encodings 3, 1 is for Unicode
728         *                         3, 0 is for Non-Unicode (ie symbols)
729         * For Macintosh encodings 1, 0 is for Roman character set
730         * For Unicode encodings   0, 3 is for Unicode
731         */
732     switch(ffile->textEncoding)
733     {
734         case kStringEncoding_ASCII:
735             // first choice
736             ffile->info->platformID[0] = 1;
737             ffile->info->specificID[0] = 0;
738             // second choice
739             ffile->info->platformID[1] = 3;
740             ffile->info->specificID[1] = 1;
741             // third choice
742             ffile->info->platformID[2] = 0;
743             ffile->info->specificID[2] = 3;
744             // fourth choice
745             ffile->info->platformID[3] = 3;
746             ffile->info->specificID[3] = 0;
747             break;
748         case kStringEncoding_UTF8:
749         case kStringEncoding_System:
750             // first choice
751             ffile->info->platformID[0] = 0;
752             ffile->info->specificID[0] = 3;
753             // second choice
754             ffile->info->platformID[1] = 3;
755             ffile->info->specificID[1] = 1;
756             // third choice
757             ffile->info->platformID[2] = 1;
758             ffile->info->specificID[2] = 0;
759             // fourth choice
760             ffile->info->platformID[3] = 3;
761             ffile->info->specificID[3] = 0;
762             break;
763     }
764 
765     /*
766      * Read the initial directory header on the TTF.  The numTables variable
767      * tells us how many tables are present in this file.
768      */
769     /// @compat
770     /// This piece of code relies on BYTE having the same size as char.
771     if (!ffile->fp->read(reinterpret_cast<char *>(&temp_tag), sizeof(BYTE) * 4))
772     {
773         throw POV_EXCEPTION(kFileDataErr, "Cannot read TrueType font file table tag");
774     }
775     if (compare_tag4(temp_tag, tag_TTCFontFile))
776     {
777         READFIXED(ffile->fp); // header version - ignored [trf]
778         READULONG(ffile->fp); // directory count - ignored [trf]
779         // go to first font data block listed in the directory table entry [trf]
780         ffile->fp->seekg(READULONG(ffile->fp), IOBase::seek_set);
781     }
782     else
783     {
784         // if it is no TTC style file, it is a regular TTF style file
785         ffile->fp->seekg(0, IOBase::seek_set);
786     }
787 
788     OffsetTable.version = READFIXED(ffile->fp);
789     OffsetTable.numTables = READUSHORT(ffile->fp);
790     OffsetTable.searchRange = READUSHORT(ffile->fp);
791     OffsetTable.entrySelector = READUSHORT(ffile->fp);
792     OffsetTable.rangeShift = READUSHORT(ffile->fp);
793 
794 #ifdef TTF_DEBUG
795     Debug_Info("OffsetTable:\n");
796     Debug_Info("version=%d\n", OffsetTable.version);
797     Debug_Info("numTables=%u\n", OffsetTable.numTables);
798     Debug_Info("searchRange=%u\n", OffsetTable.searchRange);
799     Debug_Info("entrySelector=%u\n", OffsetTable.entrySelector);
800     Debug_Info("rangeShift=%u\n", OffsetTable.rangeShift);
801 #endif
802 
803     /*
804      * I don't know why we limit this to 40 tables, since the spec says there
805      * can be any number, but that's how it was when I got it.  Added a warning
806      * just in case it ever happens in real life. [AED]
807      */
808     if (OffsetTable.numTables > 40)
809     {
810 // TODO MESSAGE    Warning("More than 40 (%d) TTF Tables in %s - some info may be lost!",
811 //            OffsetTable.numTables, ffile->filename.c_str());
812     }
813 
814     /* Process general font information and save it. */
815 
816     for (i = 0; i < OffsetTable.numTables && i < 40; i++)
817     {
818         /// @compat
819         /// This piece of code relies on BYTE having the same size as char.
820         if (!ffile->fp->read(reinterpret_cast<char *>(&Table.tag), sizeof(BYTE) * 4))
821         {
822             throw POV_EXCEPTION(kFileDataErr, "Cannot read TrueType font file table tag");
823         }
824         Table.checkSum = READULONG(ffile->fp);
825         Table.offset   = READULONG(ffile->fp);
826         Table.length   = READULONG(ffile->fp);
827 
828 #ifdef TTF_DEBUG
829         Debug_Info("\nTable %d:\n",i);
830         Debug_Info("tag=%c%c%c%c\n", Table.tag[0], Table.tag[1],
831                                      Table.tag[2], Table.tag[3]);
832         Debug_Info("checkSum=%u\n", Table.checkSum);
833         Debug_Info("offset=%u\n", Table.offset);
834         Debug_Info("length=%u\n", Table.length);
835 #endif
836 
837         if (compare_tag4(Table.tag, tag_CharToIndexMap))
838             ffile->info->cmap_table_offset = Table.offset;
839         else if (compare_tag4(Table.tag, tag_GlyphData))
840             ffile->info->glyf_table_offset = Table.offset;
841         else if (compare_tag4(Table.tag, tag_FontHeader))
842             head_table_offset = Table.offset;
843         else if (compare_tag4(Table.tag, tag_IndexToLoc))
844             loca_table_offset = Table.offset;
845         else if (compare_tag4(Table.tag, tag_MaxProfile))
846             maxp_table_offset = Table.offset;
847         else if (compare_tag4(Table.tag, tag_Kerning))
848             kern_table_offset = Table.offset;
849         else if (compare_tag4(Table.tag, tag_HorizHeader))
850             hhea_table_offset = Table.offset;
851         else if (compare_tag4(Table.tag, tag_HorizMetric))
852             hmtx_table_offset = Table.offset;
853     }
854 
855     if (ffile->info->cmap_table_offset == 0 || ffile->info->glyf_table_offset == 0 ||
856         head_table_offset == 0 || loca_table_offset == 0 ||
857         hhea_table_offset == 0 || hmtx_table_offset == 0 ||
858         maxp_table_offset == 0)
859     {
860 // TODO MESSAGE    throw POV_EXCEPTION(kFileDataErr, "Invalid TrueType font headers in %s", ffile->filename.c_str());
861     }
862 
863     ProcessHeadTable(ffile, head_table_offset);  /* Need indexToLocFormat */
864     if ((ffile->info->indexToLocFormat != 0 && ffile->info->indexToLocFormat != 1) ||
865         (ffile->info->unitsPerEm < 16 || ffile->info->unitsPerEm > 16384))
866 ;// TODO MESSAGE    Error("Invalid TrueType font data in %s", ffile->filename.c_str());
867 
868     ProcessMaxpTable(ffile, maxp_table_offset);  /* Need numGlyphs */
869     if (ffile->info->numGlyphs <= 0)
870 ;// TODO MESSAGE    Error("Invalid TrueType font data in %s", ffile->filename.c_str());
871 
872     ProcessLocaTable(ffile, loca_table_offset);  /* Now we can do loca_table */
873 
874     ProcessHheaTable(ffile, hhea_table_offset);  /* Need numberOfHMetrics */
875     if (ffile->info->numberOfHMetrics <= 0)
876 ;// TODO MESSAGE    Error("Invalid TrueType font data in %s", ffile->filename.c_str());
877 
878     ProcessHmtxTable(ffile, hmtx_table_offset);  /* Now we can read HMetrics */
879 
880     if (kern_table_offset != 0)
881         ProcessKernTable(ffile, kern_table_offset);
882 }
883 
884 /* Process the font header table */
ProcessHeadTable(TrueTypeFont * ffile,int head_table_offset)885 void ProcessHeadTable(TrueTypeFont *ffile, int head_table_offset)
886 {
887     sfnt_FontHeader fontHeader;
888 
889     /* Read head table */
890     ffile->fp->seekg(head_table_offset);
891 
892     fontHeader.version = READFIXED(ffile->fp);
893     fontHeader.fontRevision = READFIXED(ffile->fp);
894     fontHeader.checkSumAdjustment = READULONG(ffile->fp);
895     fontHeader.magicNumber = READULONG(ffile->fp);   /* should be 0x5F0F3CF5 */
896     fontHeader.flags = READUSHORT(ffile->fp);
897     fontHeader.unitsPerEm = READUSHORT(ffile->fp);
898     fontHeader.created.bc = READULONG(ffile->fp);
899     fontHeader.created.ad = READULONG(ffile->fp);
900     fontHeader.modified.bc = READULONG(ffile->fp);
901     fontHeader.modified.ad = READULONG(ffile->fp);
902     fontHeader.xMin = READFWORD(ffile->fp);
903     fontHeader.yMin = READFWORD(ffile->fp);
904     fontHeader.xMax = READFWORD(ffile->fp);
905     fontHeader.yMax = READFWORD(ffile->fp);
906     fontHeader.macStyle = READUSHORT(ffile->fp);
907     fontHeader.lowestRecPPEM = READUSHORT(ffile->fp);
908     fontHeader.fontDirectionHint = READSHORT(ffile->fp);
909     fontHeader.indexToLocFormat = READSHORT(ffile->fp);
910     fontHeader.glyphDataFormat = READSHORT(ffile->fp);
911 
912 #ifdef TTF_DEBUG
913     Debug_Info("\nfontHeader:\n");
914     Debug_Info("version: %d\n",fontHeader.version);
915     Debug_Info("fontRevision: %d\n",fontHeader.fontRevision);
916     Debug_Info("checkSumAdjustment: %u\n",fontHeader.checkSumAdjustment);
917     Debug_Info("magicNumber: 0x%8X\n",fontHeader.magicNumber);
918     Debug_Info("flags: %u\n",fontHeader.flags);
919     Debug_Info("unitsPerEm: %u\n",fontHeader.unitsPerEm);
920     Debug_Info("created.bc: %u\n",fontHeader.created.bc);
921     Debug_Info("created.ad: %u\n",fontHeader.created.ad);
922     Debug_Info("modified.bc: %u\n",fontHeader.modified.bc);
923     Debug_Info("modified.ad: %u\n",fontHeader.modified.ad);
924     Debug_Info("xMin: %d\n",fontHeader.xMin);
925     Debug_Info("yMin: %d\n",fontHeader.yMin);
926     Debug_Info("xMax: %d\n",fontHeader.xMax);
927     Debug_Info("yMax: %d\n",fontHeader.yMax);
928     Debug_Info("macStyle: %u\n",fontHeader.macStyle);
929     Debug_Info("lowestRecPPEM: %u\n",fontHeader.lowestRecPPEM);
930     Debug_Info("fontDirectionHint: %d\n",fontHeader.fontDirectionHint);
931     Debug_Info("indexToLocFormat: %d\n",fontHeader.indexToLocFormat);
932     Debug_Info("glyphDataFormat: %d\n",fontHeader.glyphDataFormat);
933 #endif
934 
935     if (fontHeader.magicNumber != 0x5F0F3CF5)
936     {
937         throw POV_EXCEPTION(kFileDataErr, "Cannot read TrueType font.");
938     }
939 
940     ffile->info->indexToLocFormat = fontHeader.indexToLocFormat;
941     ffile->info->unitsPerEm = fontHeader.unitsPerEm;
942 }
943 
944 /* Determine the relative offsets of glyphs */
ProcessLocaTable(TrueTypeFont * ffile,int loca_table_offset)945 void ProcessLocaTable(TrueTypeFont *ffile, int loca_table_offset)
946 {
947     int i;
948 
949     /* Move to location of table in file */
950     ffile->fp->seekg(loca_table_offset);
951 
952     ffile->info->loca_table = new ULONG[ffile->info->numGlyphs+1];
953 
954 #ifdef TTF_DEBUG
955     Debug_Info("\nlocation table:\n");
956     Debug_Info("version: %s\n",(ffile->info->indexToLocFormat?"long":"short"));
957 #endif
958 
959     /* Now read and save the location table */
960 
961     if (ffile->info->indexToLocFormat == 0)                  /* short version */
962     {
963         for (i = 0; i < ffile->info->numGlyphs; i++)
964         {
965             ffile->info->loca_table[i] = ((ULONG)READUSHORT(ffile->fp)) << 1;
966 #ifdef TTF_DEBUG2
967             Debug_Info("loca_table[%d] @ %u\n", i, ffile->info->loca_table[i]);
968 #endif
969         }
970     }
971     else                                               /* long version */
972     {
973         for (i = 0; i < ffile->info->numGlyphs; i++)
974         {
975             ffile->info->loca_table[i] = READULONG(ffile->fp);
976 #ifdef TTF_DEBUG2
977             Debug_Info("loca_table[%d] @ %u\n", i, ffile->info->loca_table[i]);
978 #endif
979         }
980     }
981 }
982 
983 
984 /*
985  * This routine determines the total number of glyphs in a TrueType file.
986  * Necessary so that we can allocate the proper amount of storage for the glyph
987  * location table.
988  */
ProcessMaxpTable(TrueTypeFont * ffile,int maxp_table_offset)989 void ProcessMaxpTable(TrueTypeFont *ffile, int maxp_table_offset)
990 {
991     /* seekg to the maxp table, skipping the 4 byte version number */
992     ffile->fp->seekg(maxp_table_offset + 4);
993 
994     ffile->info->numGlyphs = READUSHORT(ffile->fp);
995 
996 #ifdef TTF_DEBUG
997     Debug_Info("\nmaximum profile table:\n");
998     Debug_Info("numGlyphs: %u\n", ffile->info->numGlyphs);
999 #endif
1000 }
1001 
1002 
1003 /* Read the kerning information for a glyph */
ProcessKernTable(TrueTypeFont * ffile,int kern_table_offset)1004 void ProcessKernTable(TrueTypeFont *ffile, int kern_table_offset)
1005 {
1006     int i, j;
1007     USHORT temp16;
1008     USHORT length;
1009     KernTables *kern_table;
1010 
1011     kern_table = &ffile->info->kerning_tables;
1012 
1013     /* Move to the beginning of the kerning table, skipping the 2 byte version */
1014     ffile->fp->seekg(kern_table_offset + 2);
1015 
1016     /* Read in the number of kerning tables */
1017 
1018     kern_table->nTables = READUSHORT(ffile->fp);
1019     kern_table->tables = nullptr;      /*<==[esp] added (in case nTables is zero)*/
1020 
1021 #ifdef TTF_DEBUG
1022     Debug_Info("\nKerning table:\n", kern_table_offset);
1023     Debug_Info("Offset: %d\n", kern_table_offset);
1024     Debug_Info("Number of tables: %u\n",kern_table->nTables);
1025 #endif
1026 
1027     /* Don't do any more work if there isn't kerning info */
1028 
1029     if (kern_table->nTables == 0)
1030         return;
1031 
1032     kern_table->tables = new TTKernTable[kern_table->nTables];
1033 
1034     for (i = 0; i < kern_table->nTables; i++)
1035     {
1036         /* Read in a subtable */
1037 
1038         temp16 = READUSHORT(ffile->fp);                      /* Subtable version */
1039         length = READUSHORT(ffile->fp);                       /* Subtable length */
1040         kern_table->tables[i].coverage = READUSHORT(ffile->fp); /* Coverage bits */
1041 
1042 #ifdef TTF_DEBUG
1043         Debug_Info("Coverage table[%d] (0x%X):", i, kern_table->tables[i].coverage);
1044         Debug_Info("  type %u", (kern_table->tables[i].coverage >> 8));
1045         Debug_Info(" %s", (kern_table->tables[i].coverage & KERN_HORIZONTAL ?
1046                              "Horizontal" : "Vertical" ));
1047         Debug_Info(" %s values", (kern_table->tables[i].coverage & KERN_MINIMUM ?
1048                              "Minimum" : "Kerning" ));
1049         Debug_Info("%s", (kern_table->tables[i].coverage & KERN_CROSS_STREAM ?
1050                              " Cross-stream" : "" ));
1051         Debug_Info("%s\n", (kern_table->tables[i].coverage & KERN_OVERRIDE ?
1052                              " Override" : "" ));
1053 #endif
1054 
1055         kern_table->tables[i].kern_pairs = nullptr;/*<==[esp] added*/
1056         kern_table->tables[i].nPairs = 0;          /*<==[esp] added*/
1057 
1058         if ((kern_table->tables[i].coverage >> 8) == 0)
1059         {
1060             /* Can only handle format 0 kerning subtables */
1061             kern_table->tables[i].nPairs = READUSHORT(ffile->fp);
1062 
1063 #ifdef TTF_DEBUG
1064             Debug_Info("entries in table[%d]: %d\n", i, kern_table->tables[i].nPairs);
1065 #endif
1066 
1067             temp16 = READUSHORT(ffile->fp);     /* searchRange */
1068             temp16 = READUSHORT(ffile->fp);     /* entrySelector */
1069             temp16 = READUSHORT(ffile->fp);     /* rangeShift */
1070 
1071             kern_table->tables[i].kern_pairs = new KernData[kern_table->tables[i].nPairs];
1072 
1073             for (j = 0; j < kern_table->tables[i].nPairs; j++)
1074             {
1075                 /* Read in a kerning pair */
1076                 kern_table->tables[i].kern_pairs[j].left = READUSHORT(ffile->fp);
1077                 kern_table->tables[i].kern_pairs[j].right = READUSHORT(ffile->fp);
1078                 kern_table->tables[i].kern_pairs[j].value = READFWORD(ffile->fp);
1079 
1080 #ifdef TTF_DEBUG2
1081                 Debug_Info("Kern pair: <%d,%d> = %d\n",
1082                            (int)kern_table->tables[i].kern_pairs[j].left,
1083                            (int)kern_table->tables[i].kern_pairs[j].right,
1084                            (int)kern_table->tables[i].kern_pairs[j].value);
1085 #endif
1086             }
1087         }
1088         else
1089         {
1090 #ifdef TTF_DEBUG2
1091             Warning("Cannot handle format %u kerning data",
1092                     (kern_table->tables[i].coverage >> 8));
1093 #endif
1094             /*
1095              * seekg to the end of this table, excluding the length of the version,
1096              * length, and coverage USHORTs, which we have already read.
1097              */
1098             ffile->fp->seekg((int)(length - 6), IOBase::seek_cur);
1099             kern_table->tables[i].nPairs = 0;
1100         }
1101     }
1102 }
1103 
1104 /*
1105  * This routine determines the total number of horizontal metrics.
1106  */
ProcessHheaTable(TrueTypeFont * ffile,int hhea_table_offset)1107 void ProcessHheaTable(TrueTypeFont *ffile, int hhea_table_offset)
1108 {
1109 #ifdef TTF_DEBUG
1110     sfnt_HorizHeader horizHeader;
1111 
1112     /* seekg to the hhea table */
1113     ffile->fp->seekg(hhea_table_offset);
1114 
1115     horizHeader.version = READFIXED(ffile->fp);
1116     horizHeader.Ascender = READFWORD(ffile->fp);
1117     horizHeader.Descender = READFWORD(ffile->fp);
1118     horizHeader.LineGap = READFWORD(ffile->fp);
1119     horizHeader.advanceWidthMax = READUFWORD(ffile->fp);
1120     horizHeader.minLeftSideBearing = READFWORD(ffile->fp);
1121     horizHeader.minRightSideBearing = READFWORD(ffile->fp);
1122     horizHeader.xMaxExtent = READFWORD(ffile->fp);
1123     horizHeader.caretSlopeRise = READSHORT(ffile->fp);
1124     horizHeader.caretSlopeRun = READSHORT(ffile->fp);
1125     horizHeader.reserved1 = READSHORT(ffile->fp);
1126     horizHeader.reserved2 = READSHORT(ffile->fp);
1127     horizHeader.reserved3 = READSHORT(ffile->fp);
1128     horizHeader.reserved4 = READSHORT(ffile->fp);
1129     horizHeader.reserved5 = READSHORT(ffile->fp);
1130     horizHeader.metricDataFormat = READSHORT(ffile->fp);
1131 #else
1132 
1133     /* seekg to the hhea table, skipping all that stuff we don't need */
1134     ffile->fp->seekg (hhea_table_offset + 34);
1135 
1136 #endif
1137 
1138     ffile->info->numberOfHMetrics = READUSHORT(ffile->fp);
1139 
1140 #ifdef TTF_DEBUG
1141     Debug_Info("\nhorizontal header table:\n");
1142     Debug_Info("Ascender: %d\n",horizHeader.Ascender);
1143     Debug_Info("Descender: %d\n",horizHeader.Descender);
1144     Debug_Info("LineGap: %d\n",horizHeader.LineGap);
1145     Debug_Info("advanceWidthMax: %d\n",horizHeader.advanceWidthMax);
1146     Debug_Info("minLeftSideBearing: %d\n",horizHeader.minLeftSideBearing);
1147     Debug_Info("minRightSideBearing: %d\n",horizHeader.minRightSideBearing);
1148     Debug_Info("xMaxExtent: %d\n",horizHeader.xMaxExtent);
1149     Debug_Info("caretSlopeRise: %d\n",horizHeader.caretSlopeRise);
1150     Debug_Info("caretSlopeRun: %d\n",horizHeader.caretSlopeRun);
1151     Debug_Info("metricDataFormat: %d\n",horizHeader.metricDataFormat);
1152     Debug_Info("numberOfHMetrics: %d\n",ffile->numberOfHMetrics);
1153 #endif
1154 }
1155 
ProcessHmtxTable(TrueTypeFont * ffile,int hmtx_table_offset)1156 void ProcessHmtxTable (TrueTypeFont *ffile, int hmtx_table_offset)
1157 {
1158     int i;
1159     longHorMetric *metric;
1160     uFWord lastAW = 0;     /* Just to quiet warnings. */
1161 
1162     ffile->fp->seekg (hmtx_table_offset);
1163 
1164     ffile->info->hmtx_table = new longHorMetric[ffile->info->numGlyphs];
1165 
1166     /*
1167      * Read in the total glyph width, and the left side offset.  There is
1168      * guaranteed to be at least one longHorMetric entry in this table to
1169      * set the advanceWidth for the subsequent lsb entries.
1170      */
1171     for (i=0, metric=ffile->info->hmtx_table; i < ffile->info->numberOfHMetrics; i++,metric++)
1172     {
1173         lastAW = metric->advanceWidth = READUFWORD(ffile->fp);
1174         metric->lsb = READFWORD(ffile->fp);
1175     }
1176 
1177     /* Read in the remaining left offsets */
1178     for (; i < ffile->info->numGlyphs; i++, metric++)
1179     {
1180         metric->advanceWidth = lastAW;
1181         metric->lsb = READFWORD(ffile->fp);
1182     }
1183 }
1184 
1185 /*****************************************************************************
1186 *
1187 * FUNCTION
1188 *
1189 *   ProcessCharacter
1190 *
1191 * INPUT
1192 *
1193 * OUTPUT
1194 *
1195 * RETURNS
1196 *
1197 * AUTHOR
1198 *
1199 *   POV-Ray Team
1200 *
1201 * DESCRIPTION
1202 *
1203 *   Finds the glyph description for the current character.
1204 *
1205 * CHANGES
1206 *
1207 *   -
1208 *
1209 ******************************************************************************/
1210 
ProcessCharacter(TrueTypeFont * ffile,unsigned int search_char,unsigned int * glyph_index)1211 GlyphPtr ProcessCharacter(TrueTypeFont *ffile, unsigned int search_char, unsigned int *glyph_index)
1212 {
1213     GlyphPtrMap::iterator iGlyph;
1214 
1215     /* See if we have already processed this glyph */
1216     iGlyph = ffile->info->glyphsByChar.find(search_char);
1217     if (iGlyph != ffile->info->glyphsByChar.end())
1218     {
1219         /* Found it, no need to do any more work */
1220 #ifdef TTF_DEBUG
1221         Debug_Info("Cached glyph: %c/%u\n",(char)search_char,(*iGlyph).second->glyph_index);
1222 #endif
1223         *glyph_index = (*iGlyph).second->glyph_index;
1224         return (*iGlyph).second;
1225     }
1226 
1227     *glyph_index = ProcessCharMap(ffile, search_char);
1228     if (*glyph_index == 0)
1229 ;// TODO MESSAGE    Warning("Character %d (0x%X) not found in %s", (BYTE)search_char,
1230 //            search_char, ffile->filename.c_str());
1231 
1232     /* See if we have already processed this glyph (using the glyph index) */
1233     iGlyph = ffile->info->glyphsByIndex.find(*glyph_index);
1234     if (iGlyph != ffile->info->glyphsByIndex.end())
1235     {
1236         /* Found it, no need to do any more work (except remember the char-to-glyph mapping for next time) */
1237         ffile->info->glyphsByChar[search_char] = (*iGlyph).second;
1238 #ifdef TTF_DEBUG
1239         Debug_Info("Cached glyph: %c/%u\n",(char)search_char,(*iGlyph).second->glyph_index);
1240 #endif
1241         *glyph_index = (*iGlyph).second->glyph_index;
1242         return (*iGlyph).second;
1243     }
1244 
1245     GlyphPtr glyph = ExtractGlyphInfo(ffile, *glyph_index, search_char);
1246 
1247     /* Add this glyph to the ones we already know about */
1248 
1249     ffile->info->glyphsByChar[search_char] = glyph;
1250     ffile->info->glyphsByIndex[*glyph_index] = glyph;
1251 
1252     /* Glyph is all built */
1253 
1254     return glyph;
1255 }
1256 
1257 /*****************************************************************************
1258 *
1259 * FUNCTION
1260 *
1261 *   ProcessCharMap
1262 *
1263 * INPUT
1264 *
1265 * OUTPUT
1266 *
1267 * RETURNS
1268 *
1269 * AUTHOR
1270 *
1271 *   POV-Ray Team
1272 *
1273 * DESCRIPTION
1274 *
1275 *   Find the character mapping for 'search_char'.  We should really know
1276 *   which character set we are using (ie ISO 8859-1, Mac, Unicode, etc).
1277 *   Search char should really be a USHORT to handle double byte systems.
1278 *
1279 * CHANGES
1280 *
1281 *   961120  esp  Added check to allow Macintosh encodings to pass
1282 *
1283 ******************************************************************************/
ProcessCharMap(TrueTypeFont * ffile,unsigned int search_char)1284 USHORT ProcessCharMap(TrueTypeFont *ffile, unsigned int search_char)
1285 {
1286     int initial_table_offset;
1287     int old_table_offset;
1288     int entry_offset;
1289     sfnt_platformEntry cmapEntry;
1290     sfnt_mappingTable encodingTable;
1291     int i, j, table_count;
1292 
1293     /* Move to the start of the character map, skipping the 2 byte version */
1294     ffile->fp->seekg (ffile->info->cmap_table_offset + 2);
1295 
1296     table_count = READUSHORT(ffile->fp);
1297 
1298     #ifdef TTF_DEBUG
1299     Debug_Info("table_count=%d\n", table_count);
1300     #endif
1301 
1302     /*
1303      * Search the tables until we find the glyph index for the search character.
1304      * Just return the first one we find...
1305      */
1306 
1307     initial_table_offset = ffile->fp->tellg (); /* Save the initial position */
1308 
1309     for(j = 0; j <= 3; j++)
1310     {
1311         ffile->fp->seekg(initial_table_offset); /* Always start new search at the initial position */
1312 
1313         for (i = 0; i < table_count; i++)
1314         {
1315             cmapEntry.platformID = READUSHORT(ffile->fp);
1316             cmapEntry.specificID = READUSHORT(ffile->fp);
1317             cmapEntry.offset     = READULONG(ffile->fp);
1318 
1319             #ifdef TTF_DEBUG
1320             Debug_Info("cmapEntry: platformID=%d\n", cmapEntry.platformID);
1321             Debug_Info("cmapEntry: specificID=%d\n", cmapEntry.specificID);
1322             Debug_Info("cmapEntry: offset=%d\n", cmapEntry.offset);
1323             #endif
1324 
1325             /*
1326              * Check if this is the encoding table we want to use.
1327              * The search is done according to user preference.
1328              */
1329             if ( ffile->info->platformID[j] != cmapEntry.platformID ) /* [JAC 01/99] */
1330             {
1331                 continue;
1332             }
1333 
1334             entry_offset = cmapEntry.offset;
1335 
1336             old_table_offset = ffile->fp->tellg (); /* Save the current position */
1337 
1338             ffile->fp->seekg (ffile->info->cmap_table_offset + entry_offset);
1339 
1340             encodingTable.format = READUSHORT(ffile->fp);
1341             encodingTable.length = READUSHORT(ffile->fp);
1342             encodingTable.version = READUSHORT(ffile->fp);
1343 
1344             #ifdef TTF_DEBUG
1345             Debug_Info("Encoding table, format: %u, length: %u, version: %u\n",
1346                        encodingTable.format, encodingTable.length, encodingTable.version);
1347             #endif
1348 
1349             if (encodingTable.format == 0)
1350             {
1351                 /*
1352                  * Translation is simple - add 'entry_char' to the start of the
1353                  * table and grab what's there.
1354                  */
1355                 #ifdef TTF_DEBUG
1356                 Debug_Info("Apple standard index mapping\n");
1357                 #endif
1358 
1359                 return(ProcessFormat0Glyph(ffile, search_char));
1360             }
1361             #if 0  /* Want to get the rest of these working first */
1362             else if (encodingTable.format == 2)
1363             {
1364                 /* Used for multi-byte character encoding (Chinese, Japanese, etc) */
1365                 #ifdef TTF_DEBUG
1366                 Debug_Info("High-byte index mapping\n");
1367                 #endif
1368 
1369                 return(ProcessFormat2Glyph(ffile, search_char));
1370             }
1371             #endif
1372             else if (encodingTable.format == 4)
1373             {
1374                 /* Microsoft UGL encoding */
1375                 #ifdef TTF_DEBUG
1376                 Debug_Info("Microsoft standard index mapping\n");
1377                 #endif
1378 
1379                 return(ProcessFormat4Glyph(ffile, search_char));
1380             }
1381             else if (encodingTable.format == 6)
1382             {
1383                 #ifdef TTF_DEBUG
1384                 Debug_Info("Trimmed table mapping\n");
1385                 #endif
1386 
1387                 return(ProcessFormat6Glyph(ffile, search_char));
1388             }
1389             #ifdef TTF_DEBUG
1390             else
1391                 Debug_Info("Unsupported TrueType font index mapping format: %u\n",
1392                            encodingTable.format);
1393             #endif
1394 
1395             /* Go to the next table entry if we didn't find a match */
1396             ffile->fp->seekg (old_table_offset);
1397         }
1398     }
1399 
1400     /*
1401      * No character mapping was found - very odd, we should really have had the
1402      * character in at least one table.  Perhaps getting here means we didn't
1403      * have any character mapping tables.  '0' means no mapping.
1404      */
1405 
1406     return 0;
1407 }
1408 
1409 
1410 /*****************************************************************************
1411 *
1412 * FUNCTION
1413 *
1414 *   ProcessFormat0Glyph
1415 *
1416 * INPUT
1417 *
1418 * OUTPUT
1419 *
1420 * RETURNS
1421 *
1422 * AUTHOR
1423 *
1424 *   POV-Ray Team
1425 *
1426 * DESCRIPTION
1427 *
1428 * This handles the Apple standard index mapping for glyphs.
1429 * The file pointer must be pointing immediately after the version entry in the
1430 * encoding table for the next two functions to work.
1431 *
1432 * CHANGES
1433 *
1434 *   -
1435 *
1436 ******************************************************************************/
ProcessFormat0Glyph(TrueTypeFont * ffile,unsigned int search_char)1437 USHORT ProcessFormat0Glyph(TrueTypeFont *ffile, unsigned int search_char)
1438 {
1439     BYTE temp_index;
1440 
1441     ffile->fp->seekg ((int)search_char, IOBase::seek_cur);
1442 
1443     /// @compat
1444     /// This piece of code relies on BYTE having the same size as char.
1445     if (!ffile->fp->read (reinterpret_cast<char *>(&temp_index), 1)) /* Each index is 1 byte */
1446     {
1447         throw POV_EXCEPTION(kFileDataErr, "Cannot read TrueType font file.");
1448     }
1449 
1450     return (USHORT)(temp_index);
1451 }
1452 
1453 /*****************************************************************************
1454 *
1455 * FUNCTION
1456 *
1457 *   ProcessFormat4Glyph
1458 *
1459 * INPUT
1460 *
1461 * OUTPUT
1462 *
1463 * RETURNS
1464 *
1465 * AUTHOR
1466 *
1467 *   POV-Ray Team
1468 *
1469 * DESCRIPTION
1470 *
1471 * This handles the Microsoft standard index mapping for glyph tables
1472 *
1473 * CHANGES
1474 *
1475 *   Mar 26, 1996: Cache segment info rather than read each time.  [AED]
1476 *
1477 ******************************************************************************/
ProcessFormat4Glyph(TrueTypeFont * ffile,unsigned int search_char)1478 USHORT ProcessFormat4Glyph(TrueTypeFont *ffile, unsigned int search_char)
1479 {
1480     int i;
1481     unsigned int glyph_index = 0;  /* Set the glyph index to "not present" */
1482 
1483     /*
1484      * If this is the first time we are here, read all of the segment headers,
1485      * and save them for later calls to this function, rather than seeking and
1486      * mallocing for each character
1487      */
1488     if (ffile->info->segCount == 0)
1489     {
1490         USHORT temp16;
1491 
1492         ffile->info->segCount = READUSHORT(ffile->fp) >> 1;
1493         ffile->info->searchRange = READUSHORT(ffile->fp);
1494         ffile->info->entrySelector = READUSHORT(ffile->fp);
1495         ffile->info->rangeShift = READUSHORT(ffile->fp);
1496 
1497         /* Now allocate and read in the segment arrays */
1498 
1499         ffile->info->endCount = new USHORT[ffile->info->segCount];
1500         ffile->info->startCount = new USHORT[ffile->info->segCount];
1501         ffile->info->idDelta = new USHORT[ffile->info->segCount];
1502         ffile->info->idRangeOffset = new USHORT[ffile->info->segCount];
1503 
1504         for (i = 0; i < ffile->info->segCount; i++)
1505         {
1506             ffile->info->endCount[i] = READUSHORT(ffile->fp);
1507         }
1508 
1509         temp16 = READUSHORT(ffile->fp);  /* Skip over 'reservedPad' */
1510 
1511         for (i = 0; i < ffile->info->segCount; i++)
1512         {
1513             ffile->info->startCount[i] = READUSHORT(ffile->fp);
1514         }
1515 
1516         for (i = 0; i < ffile->info->segCount; i++)
1517         {
1518             ffile->info->idDelta[i] = READUSHORT(ffile->fp);
1519         }
1520 
1521         /* location of start of idRangeOffset */
1522         ffile->info->glyphIDoffset = ffile->fp->tellg ();
1523 
1524         for (i = 0; i < ffile->info->segCount; i++)
1525         {
1526             ffile->info->idRangeOffset[i] = READUSHORT(ffile->fp);
1527         }
1528     }
1529 
1530     /* Search the segments for our character */
1531 
1532 glyph_search:
1533     for (i = 0; i < ffile->info->segCount; i++)
1534     {
1535         if (search_char <= ffile->info->endCount[i])
1536         {
1537             if (search_char >= ffile->info->startCount[i])
1538             {
1539                 /* Found correct range for this character */
1540 
1541                 if (ffile->info->idRangeOffset[i] == 0)
1542                 {
1543                     glyph_index = search_char + ffile->info->idDelta[i];
1544                 }
1545                 else
1546                 {
1547                     /*
1548                      * Alternate encoding of glyph indices, relies on a quite unusual way
1549                      * of storing the offsets.  We need the *2s because we are talking
1550                      * about addresses of shorts and not bytes.
1551                      *
1552                      * (glyphIDoffset + i*2 + idRangeOffset[i]) == &idRangeOffset[i]
1553                      */
1554                     ffile->fp->seekg (ffile->info->glyphIDoffset + 2*i + ffile->info->idRangeOffset[i]+
1555                                      2*(search_char - ffile->info->startCount[i]));
1556 
1557                     glyph_index = READUSHORT(ffile->fp);
1558 
1559                     if (glyph_index != 0)
1560                         glyph_index = glyph_index + ffile->info->idDelta[i];
1561                 }
1562             }
1563             break;
1564         }
1565     }
1566 
1567     /*
1568      * If we haven't found the character yet, and this is the first time to
1569      * search the tables, try looking in the Unicode user space, since this
1570      * is the location Microsoft recommends for symbol characters like those
1571      * in wingdings and dingbats.
1572      */
1573     if (glyph_index == 0 && search_char < 0x100)
1574     {
1575         search_char += 0xF000;
1576 #ifdef TTF_DEBUG
1577         Debug_Info("Looking for glyph in Unicode user space (0x%X)\n", search_char);
1578 #endif
1579         goto glyph_search;
1580     }
1581 
1582     /* Deallocate the memory we used for the segment arrays */
1583 
1584     return glyph_index;
1585 }
1586 
1587 /*****************************************************************************
1588 *
1589 * FUNCTION
1590 *
1591 *   ProcessFormat6Glyph
1592 *
1593 * INPUT
1594 *
1595 * OUTPUT
1596 *
1597 * RETURNS
1598 *
1599 * AUTHOR
1600 *
1601 *   POV-Ray Team
1602 *
1603 * DESCRIPTION
1604 *
1605 *  This handles the trimmed table mapping for glyphs.
1606 *
1607 * CHANGES
1608 *
1609 *   -
1610 *
1611 ******************************************************************************/
ProcessFormat6Glyph(TrueTypeFont * ffile,unsigned int search_char)1612 USHORT ProcessFormat6Glyph(TrueTypeFont *ffile, unsigned int search_char)
1613 {
1614     USHORT firstCode, entryCount;
1615     USHORT glyph_index;
1616 
1617     firstCode = READUSHORT(ffile->fp);
1618     entryCount = READUSHORT(ffile->fp);
1619 
1620     if (search_char >= firstCode && search_char < firstCode + entryCount)
1621     {
1622         ffile->fp->seekg (((int)(search_char - firstCode))*2, IOBase::seek_cur);
1623         glyph_index = READUSHORT(ffile->fp);
1624     }
1625     else
1626         glyph_index = 0;
1627 
1628     return glyph_index;
1629 }
1630 
1631 
1632 /*****************************************************************************
1633 *
1634 * FUNCTION
1635 *
1636 *   ExtractGlyphInfo
1637 *
1638 * INPUT
1639 *
1640 * OUTPUT
1641 *
1642 * RETURNS
1643 *
1644 * AUTHOR
1645 *
1646 *   POV-Ray Team
1647 *
1648 * DESCRIPTION
1649 *
1650 *   Change TTF outline information for the glyph(s) into a useful format
1651 *
1652 * CHANGES
1653 *
1654 *   -
1655 *
1656 ******************************************************************************/
ExtractGlyphInfo(TrueTypeFont * ffile,unsigned int glyph_index,unsigned int c)1657 GlyphPtr ExtractGlyphInfo(TrueTypeFont *ffile, unsigned int glyph_index, unsigned int c)
1658 {
1659     GlyphOutline *ttglyph;
1660     GlyphPtr glyph;
1661 
1662     ttglyph = ExtractGlyphOutline(ffile, glyph_index, c);
1663     POV_SHAPE_ASSERT(ttglyph != nullptr);
1664 
1665     /*
1666      * Convert the glyph outline information from TrueType layout into a more
1667      * easily processed format
1668      */
1669 
1670     glyph = ConvertOutlineToGlyph(ffile, ttglyph);
1671     glyph->glyph_index = glyph_index;
1672     glyph->myMetrics = ttglyph->myMetrics;
1673 
1674     /* Free up outline information */
1675 
1676     delete ttglyph;
1677 
1678 #ifdef TTF_DEBUG3
1679     int i, j;
1680 
1681     Debug_Info("// Character '%c'\n", (char)c);
1682 
1683     for(i = 0; i < (int)glyph->header.numContours; i++)
1684     {
1685         Debug_Info("BYTE gGlypthFlags_%c_%d[] = \n", (char)c, i);
1686         Debug_Info("{");
1687         for(j = 0; j <= (int)glyph->contours[i].count; j++)
1688         {
1689             if((j % 10) == 0)
1690                 Debug_Info("\n\t");
1691             Debug_Info("0x%x, ", (unsigned int)glyph->contours[i].flags[j]);
1692         }
1693         Debug_Info("\n};\n\n");
1694 
1695         Debug_Info("DBL gGlypthX_%c_%d[] = \n", (char)c, i);
1696         Debug_Info("{");
1697         for(j = 0; j <= (int)glyph->contours[i].count; j++)
1698         {
1699             if((j % 10) == 0)
1700                 Debug_Info("\n\t");
1701             Debug_Info("%f, ", (DBL)glyph->contours[i].x[j]);
1702         }
1703         Debug_Info("\n};\n\n");
1704 
1705         Debug_Info("DBL gGlypthY_%c_%d[] = \n", (char)c, i);
1706         Debug_Info("{");
1707         for(j = 0; j <= (int)glyph->contours[i].count; j++)
1708         {
1709             if((j % 10) == 0)
1710                 Debug_Info("\n\t");
1711             Debug_Info("%f, ", (DBL)glyph->contours[i].y[j]);
1712         }
1713         Debug_Info("\n};\n\n");
1714     }
1715 
1716     Debug_Info("Contour gGlypthContour_%c[] = \n", (char)c);
1717     Debug_Info("{\n");
1718     for(i = 0; i < glyph->header.numContours; i++)
1719     {
1720         Debug_Info("\t{\n");
1721         Debug_Info("\t\t%u, // inside_flag \n", (unsigned int)glyph->contours[i].inside_flag);
1722         Debug_Info("\t\t%u, // count \n", (unsigned int)glyph->contours[i].count);
1723         Debug_Info("\t\tgGlypthFlags_%c_%d, // flags[]\n", (char)c, i);
1724         Debug_Info("\t\tgGlypthX_%c_%d, // x[]\n", (char)c, i);
1725         Debug_Info("\t\tgGlypthY_%c_%d // y[]\n", (char)c, i);
1726         Debug_Info("\t},\n");
1727     }
1728     Debug_Info("\n};\n\n");
1729 
1730     Debug_Info("Glyph gGlypth_%c = \n", (char)c);
1731     Debug_Info("{\n");
1732     Debug_Info("\t{ // header\n");
1733     Debug_Info("\t\t%u, // header.numContours \n", (unsigned int)glyph->header.numContours);
1734     Debug_Info("\t\t%f, // header.xMin\n", (DBL)glyph->header.xMin);
1735     Debug_Info("\t\t%f, // header.yMin\n", (DBL)glyph->header.yMin);
1736     Debug_Info("\t\t%f, // header.xMax\n", (DBL)glyph->header.xMax);
1737     Debug_Info("\t\t%f // header.yMax\n", (DBL)glyph->header.yMax);
1738     Debug_Info("\t},\n");
1739     Debug_Info("\t%u, // glyph_index\n", (unsigned int)glyph->glyph_index);
1740     Debug_Info("\tgGlypthContour_%c, // contours[]\n", (char)c);
1741     Debug_Info("\t%u, // unitsPerEm\n", (unsigned int)glyph->unitsPerEm);
1742     Debug_Info("\tNULL, // next\n");
1743     Debug_Info("\t%u, // c\n", (unsigned int)glyph->c);
1744     Debug_Info("\t%u // myMetrics\n", (unsigned int)glyph->myMetrics);
1745 
1746     Debug_Info("};\n\n");
1747 #endif
1748 
1749     return glyph;
1750 }
1751 
1752 
1753 
1754 /*****************************************************************************
1755 *
1756 * FUNCTION
1757 *
1758 *   ExtractGlyphOutline
1759 *
1760 * INPUT
1761 *
1762 * OUTPUT
1763 *
1764 * RETURNS
1765 *
1766 * AUTHOR
1767 *
1768 *   POV-Ray Team
1769 *
1770 * DESCRIPTION
1771 *
1772 *   Read the contour information for a specific glyph.  This has to be a
1773 *   separate routine from ExtractGlyphInfo because we call it recurisvely
1774 *   for multiple component glyphs.
1775 *
1776 * CHANGES
1777 *
1778 *   -
1779 *
1780 ******************************************************************************/
ExtractGlyphOutline(TrueTypeFont * ffile,unsigned int glyph_index,unsigned int c)1781 GlyphOutline *ExtractGlyphOutline(TrueTypeFont *ffile, unsigned int glyph_index, unsigned int c)
1782 {
1783     int i;
1784     USHORT n;
1785     SHORT nc;
1786     GlyphOutline *ttglyph;
1787 
1788     ttglyph = new GlyphOutline;
1789     ttglyph->myMetrics = glyph_index;
1790 
1791     /* Have to treat space characters differently */
1792     if (c != ' ')
1793     {
1794         ffile->fp->seekg (ffile->info->glyf_table_offset+ffile->info->loca_table[glyph_index]);
1795 
1796         ttglyph->header.numContours = READSHORT(ffile->fp);
1797         ttglyph->header.xMin = READFWORD(ffile->fp);   /* These may be  */
1798         ttglyph->header.yMin = READFWORD(ffile->fp);   /* unreliable in */
1799         ttglyph->header.xMax = READFWORD(ffile->fp);   /* some fonts.   */
1800         ttglyph->header.yMax = READFWORD(ffile->fp);
1801     }
1802 
1803 #ifdef TTF_DEBUG
1804     Debug_Info("ttglyph->header:\n");
1805     Debug_Info("glyph_index=%d\n", glyph_index);
1806     Debug_Info("loca_table[%d]=%d\n",glyph_index,ffile->info->loca_table[glyph_index]);
1807     Debug_Info("numContours=%d\n", (int)ttglyph->header.numContours);
1808 #endif
1809 
1810     nc = ttglyph->header.numContours;
1811 
1812     /*
1813      * A positive number of contours means a regular glyph, with possibly
1814      * several separate line segments making up the outline.
1815      */
1816     if (nc > 0)
1817     {
1818         FWord coord;
1819         BYTE flag, repeat_count;
1820         USHORT temp16;
1821 
1822         /* Grab the contour endpoints */
1823 
1824         ttglyph->endPoints.resize(nc);
1825 
1826         for (i = 0; i < nc; i++)
1827         {
1828             ttglyph->endPoints[i] = READUSHORT(ffile->fp);
1829 #ifdef TTF_DEBUG
1830             Debug_Info("endPoints[%d]=%d\n", i, ttglyph->endPoints[i]);
1831 #endif
1832         }
1833 
1834         /* Skip over the instructions */
1835         temp16 = READUSHORT(ffile->fp);
1836         ffile->fp->seekg (temp16, IOBase::seek_cur);
1837 #ifdef TTF_DEBUG
1838         Debug_Info("skipping instruction bytes: %d\n", temp16);
1839 #endif
1840 
1841         /* Determine the number of points making up this glyph */
1842 
1843         n = ttglyph->endPoints[nc - 1] + 1;
1844 #ifdef TTF_DEBUG
1845         Debug_Info("numPoints=%d\n", n);
1846 #endif
1847 
1848         /* Read the flags */
1849 
1850         ttglyph->flags.resize(n);
1851 
1852         for (i = 0; i < n; i++)
1853         {
1854             /// @compat
1855             /// This piece of code relies on BYTE having the same size as char.
1856             if (!ffile->fp->read(reinterpret_cast<char *>(&ttglyph->flags[i]), sizeof(BYTE)))
1857             {
1858                 throw POV_EXCEPTION(kFileDataErr, "Cannot read TrueType font file.");
1859             }
1860 
1861             if (ttglyph->flags[i] & REPEAT_FLAGS)
1862             {
1863                 /// @compat
1864                 /// This piece of code relies on BYTE having the same size as char.
1865                 if (!ffile->fp->read(reinterpret_cast<char *>(&repeat_count), sizeof(BYTE)))
1866                 {
1867                     throw POV_EXCEPTION(kFileDataErr, "Cannot read TrueType font file.");
1868                 }
1869                 for (; repeat_count > 0; repeat_count--, i++)
1870                 {
1871 #ifdef TTF_DEBUG
1872                     if (i>=n)
1873                     {
1874                         Debug_Info("readflags ERROR: i >= n (%d > %d)\n", i, n);
1875                     }
1876 #endif
1877                     if (i<n)      /* hack around a bug that is trying to write too many flags */
1878                         ttglyph->flags[i + 1] = ttglyph->flags[i];
1879                 }
1880             }
1881         }
1882 #ifdef  TTF_DEBUG
1883         Debug_Info("flags:");
1884         for (i=0; i<n; i++)
1885             Debug_Info(" %02x", ttglyph->flags[i]);
1886         Debug_Info("\n");
1887 #endif
1888         /* Read the coordinate vectors */
1889 
1890         ttglyph->x.resize(n);
1891         ttglyph->y.resize(n);
1892 
1893         coord = 0;
1894 
1895         for (i = 0; i < n; i++)
1896         {
1897             /* Read each x coordinate */
1898 
1899             flag = ttglyph->flags[i];
1900 
1901             if (flag & XSHORT)
1902             {
1903                 BYTE temp8;
1904 
1905                 /// @compat
1906                 /// This piece of code relies on BYTE having the same size as char.
1907                 if (!ffile->fp->read(reinterpret_cast<char *>(&temp8), 1))
1908                 {
1909                     throw POV_EXCEPTION(kFileDataErr, "Cannot read TrueType font file.");
1910                 }
1911 
1912                 if (flag & SHORT_X_IS_POS)
1913                     coord += temp8;
1914                 else
1915                     coord -= temp8;
1916             }
1917             else if (!(flag & NEXT_X_IS_ZERO))
1918             {
1919                 coord += READSHORT(ffile->fp);
1920             }
1921 
1922             /* Find our own maximum and minimum x coordinates */
1923             if (coord > ttglyph->header.xMax)
1924                 ttglyph->header.xMax = coord;
1925             if (coord < ttglyph->header.xMin)
1926                 ttglyph->header.xMin = coord;
1927 
1928             ttglyph->x[i] = (DBL)coord / (DBL)ffile->info->unitsPerEm;
1929         }
1930 
1931         coord = 0;
1932 
1933         for (i = 0; i < n; i++)
1934         {
1935             /* Read each y coordinate */
1936 
1937             flag = ttglyph->flags[i];
1938 
1939             if (flag & YSHORT)
1940             {
1941                 BYTE temp8;
1942 
1943                 /// @compat
1944                 /// This piece of code relies on BYTE having the same size as char.
1945                 if (!ffile->fp->read(reinterpret_cast<char *>(&temp8), 1))
1946                 {
1947                     throw POV_EXCEPTION(kFileDataErr, "Cannot read TrueType font file.");
1948                 }
1949 
1950                 if (flag & SHORT_Y_IS_POS)
1951                     coord += temp8;
1952                 else
1953                     coord -= temp8;
1954             }
1955             else if (!(flag & NEXT_Y_IS_ZERO))
1956             {
1957                 coord += READSHORT(ffile->fp);
1958             }
1959 
1960             /* Find out our own maximum and minimum y coordinates */
1961             if (coord > ttglyph->header.yMax)
1962                 ttglyph->header.yMax = coord;
1963             if (coord < ttglyph->header.yMin)
1964                 ttglyph->header.yMin = coord;
1965 
1966             ttglyph->y[i] = (DBL)coord / (DBL)ffile->info->unitsPerEm;
1967         }
1968     }
1969     /*
1970      * A negative number for numContours means that this glyph is
1971      * made up of several separate glyphs.
1972      */
1973     else if (nc < 0)
1974     {
1975         USHORT flags;
1976 
1977         ttglyph->header.numContours = 0;
1978 
1979         do
1980         {
1981             GlyphOutline *sub_ttglyph;
1982             unsigned int sub_glyph_index;
1983             int   current_pos;
1984             SHORT arg1, arg2;
1985             DBL xoff = 0, yoff = 0;
1986             DBL xscale = 1, yscale = 1;
1987             DBL scale01 = 0, scale10 = 0;
1988             USHORT n2;
1989             SHORT nc2;
1990 
1991             flags = READUSHORT(ffile->fp);
1992             sub_glyph_index = READUSHORT(ffile->fp);
1993 
1994 #ifdef TTF_DEBUG
1995             Debug_Info("sub_glyph %d: ", sub_glyph_index);
1996 #endif
1997 
1998             if (flags & ARG_1_AND_2_ARE_WORDS)
1999             {
2000 #ifdef TTF_DEBUG
2001                 Debug_Info("ARG_1_AND_2_ARE_WORDS ");
2002 #endif
2003                 arg1 = READSHORT(ffile->fp);
2004                 arg2 = READSHORT(ffile->fp);
2005             }
2006             else
2007             {
2008                 arg1 = READUSHORT(ffile->fp);
2009                 arg2 = arg1 & 0xFF;
2010                 arg1 = (arg1 >> 8) & 0xFF;
2011             }
2012 
2013 #ifdef TTF_DEBUG
2014             if (flags & ROUND_XY_TO_GRID)
2015             {
2016                 Debug_Info("ROUND_XY_TO_GRID ");
2017             }
2018 
2019             if (flags & MORE_COMPONENTS)
2020             {
2021                 Debug_Info("MORE_COMPONENTS ");
2022             }
2023 #endif
2024 
2025             if (flags & WE_HAVE_A_SCALE)
2026             {
2027                 xscale = yscale = (DBL)READSHORT(ffile->fp)/0x4000;
2028 #ifdef TTF_DEBUG
2029                 Debug_Info("WE_HAVE_A_SCALE ");
2030                 Debug_Info("xscale = %lf\t", xscale);
2031                 Debug_Info("scale01 = %lf\n", scale01);
2032                 Debug_Info("scale10 = %lf\t", scale10);
2033                 Debug_Info("yscale = %lf\n", yscale);
2034 #endif
2035             }
2036             else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
2037             {
2038                 xscale = (DBL)READSHORT(ffile->fp)/0x4000;
2039                 yscale = (DBL)READSHORT(ffile->fp)/0x4000;
2040 #ifdef TTF_DEBUG
2041                 Debug_Info("WE_HAVE_AN_X_AND_Y_SCALE ");
2042                 Debug_Info("xscale = %lf\t", xscale);
2043                 Debug_Info("scale01 = %lf\n", scale01);
2044                 Debug_Info("scale10 = %lf\t", scale10);
2045                 Debug_Info("yscale = %lf\n", yscale);
2046 #endif
2047             }
2048             else if (flags & WE_HAVE_A_TWO_BY_TWO)
2049             {
2050                 xscale  = (DBL)READSHORT(ffile->fp)/0x4000;
2051                 scale01 = (DBL)READSHORT(ffile->fp)/0x4000;
2052                 scale10 = (DBL)READSHORT(ffile->fp)/0x4000;
2053                 yscale  = (DBL)READSHORT(ffile->fp)/0x4000;
2054 #ifdef TTF_DEBUG
2055                 Debug_Info("WE_HAVE_A_TWO_BY_TWO ");
2056                 Debug_Info("xscale = %lf\t", xscale);
2057                 Debug_Info("scale01 = %lf\n", scale01);
2058                 Debug_Info("scale10 = %lf\t", scale10);
2059                 Debug_Info("yscale = %lf\n", yscale);
2060 #endif
2061             }
2062 
2063             if (flags & ARGS_ARE_XY_VALUES)
2064             {
2065                 xoff = (DBL)arg1 / ffile->info->unitsPerEm;
2066                 yoff = (DBL)arg2 / ffile->info->unitsPerEm;
2067 
2068 #ifdef TTF_DEBUG
2069                 Debug_Info("ARGS_ARE_XY_VALUES ");
2070                 Debug_Info("\narg1 = %d  xoff = %lf\t", arg1, xoff);
2071                 Debug_Info("arg2 = %d  yoff = %lf\n", arg2, yoff);
2072 #endif
2073             }
2074             else  /* until I understand how this method works... */
2075             {
2076 // TODO MESSAGE        Warning("Cannot handle part of glyph %d (0x%X).", c, c);
2077                 continue;
2078             }
2079 
2080             if (flags & USE_MY_METRICS)
2081             {
2082 #ifdef TTF_DEBUG
2083                 Debug_Info("USE_MY_METRICS ");
2084 #endif
2085                 ttglyph->myMetrics = sub_glyph_index;
2086             }
2087 
2088             current_pos = ffile->fp->tellg ();
2089             sub_ttglyph = ExtractGlyphOutline(ffile, sub_glyph_index, c);
2090             ffile->fp->seekg (current_pos);
2091 
2092             if ((nc2 = sub_ttglyph->header.numContours) == 0)
2093                 continue;
2094 
2095             nc = ttglyph->header.numContours;
2096             n = ttglyph->flags.size();
2097             POV_SHAPE_ASSERT((n == ttglyph->x.size()) && (n == ttglyph->y.size()));
2098             n2 = sub_ttglyph->flags.size();
2099             POV_SHAPE_ASSERT((n2 == sub_ttglyph->x.size()) && (n2 == sub_ttglyph->y.size()));
2100 
2101             ttglyph->endPoints.resize(nc + nc2);
2102             ttglyph->flags.resize(n + n2);
2103             ttglyph->x.resize(n + n2);
2104             ttglyph->y.resize(n + n2);
2105 
2106             /* Add the sub glyph info to the end of the current glyph */
2107 
2108             ttglyph->header.numContours += nc2;
2109 
2110             for (i = 0; i < nc2; i++)
2111             {
2112                 ttglyph->endPoints[i + nc] = sub_ttglyph->endPoints[i] + n;
2113 #ifdef TTF_DEBUG
2114                 Debug_Info("endPoints[%d]=%d\n", i + nc, ttglyph->endPoints[i + nc]);
2115 #endif
2116             }
2117 
2118             for (i = 0; i < n2; i++)
2119             {
2120 #ifdef TTF_DEBUG
2121                 Debug_Info("x[%d]=%lf\t", i, sub_ttglyph->x[i]);
2122                 Debug_Info("y[%d]=%lf\n", i, sub_ttglyph->y[i]);
2123 #endif
2124                 ttglyph->flags[i + n] = sub_ttglyph->flags[i];
2125                 ttglyph->x[i + n] = xscale * sub_ttglyph->x[i] +
2126                                     scale01 * sub_ttglyph->y[i] + xoff;
2127                 ttglyph->y[i + n] = scale10 * sub_ttglyph->x[i] +
2128                                     yscale * sub_ttglyph->y[i] + yoff;
2129 
2130 #ifdef TTF_DEBUG
2131                 Debug_Info("x[%d]=%lf\t", i+n, ttglyph->x[i+n]);
2132                 Debug_Info("y[%d]=%lf\n", i+n, ttglyph->y[i+n]);
2133 #endif
2134 
2135                 if (ttglyph->x[i + n] < ttglyph->header.xMin)
2136                     ttglyph->header.xMin = ttglyph->x[i + n];
2137 
2138                 if (ttglyph->x[i + n] > ttglyph->header.xMax)
2139                     ttglyph->header.xMax = ttglyph->x[i + n];
2140 
2141                 if (ttglyph->y[i + n] < ttglyph->header.yMin)
2142                     ttglyph->header.yMin = ttglyph->y[i + n];
2143 
2144                 if (ttglyph->y[i + n] > ttglyph->header.yMax)
2145                     ttglyph->header.yMax = ttglyph->y[i + n];
2146             }
2147 
2148             /* Free up the sub glyph outline information */
2149 
2150             delete sub_ttglyph;
2151         } while (flags & MORE_COMPONENTS);
2152     }
2153 
2154 #ifdef TTF_DEBUG
2155         Debug_Info("xMin=%d\n",ttglyph->header.xMin);
2156         Debug_Info("yMin=%d\n",ttglyph->header.yMin);
2157         Debug_Info("xMax=%d\n",ttglyph->header.xMax);
2158         Debug_Info("yMax=%d\n",ttglyph->header.yMax);
2159 #endif
2160 
2161     return ttglyph;
2162 }
2163 
2164 
2165 
2166 /*****************************************************************************
2167 *
2168 * FUNCTION
2169 *
2170 *   ConvertOutlineToGlyph
2171 *
2172 * INPUT
2173 *
2174 * OUTPUT
2175 *
2176 * RETURNS
2177 *
2178 * AUTHOR
2179 *
2180 *   POV-Ray Team
2181 *
2182 * DESCRIPTION
2183 *
2184 * Transform a glyph from TrueType storage format to something a little easier
2185 * to manage.
2186 *
2187 * CHANGES
2188 *
2189 *   -
2190 *
2191 ******************************************************************************/
ConvertOutlineToGlyph(TrueTypeFont * ffile,const GlyphOutline * ttglyph)2192 GlyphPtr ConvertOutlineToGlyph(TrueTypeFont *ffile, const GlyphOutline *ttglyph)
2193 {
2194     GlyphPtr glyph;
2195     USHORT i, j, last_j;
2196 
2197     /* Create storage for this glyph */
2198 
2199     glyph = new GlyphStruct;
2200     if (ttglyph->header.numContours > 0)
2201     {
2202         glyph->contours = new Contour[ttglyph->header.numContours];
2203     }
2204     else
2205     {
2206         glyph->contours = nullptr;
2207     }
2208 
2209     /* Copy sizing information about this glyph */
2210 
2211     glyph->header = ttglyph->header;
2212 
2213     /* Keep track of the size for this glyph */
2214 
2215     glyph->unitsPerEm = ffile->info->unitsPerEm;
2216 
2217     /* Now copy the vertex information into the contours */
2218 
2219     for (i = 0, last_j = 0; i < (USHORT) ttglyph->header.numContours; i++)
2220     {
2221         /* Figure out number of points in contour */
2222 
2223         j = ttglyph->endPoints[i] - last_j + 1;
2224 
2225         /* Copy the coordinate information into the glyph */
2226 
2227         glyph->contours[i].x.reserve(j + 1);
2228         glyph->contours[i].y.reserve(j + 1);
2229         glyph->contours[i].flags.reserve(j + 1);
2230         glyph->contours[i].x.assign(ttglyph->x.cbegin() + last_j, ttglyph->x.cbegin() + last_j + j);
2231         glyph->contours[i].y.assign(ttglyph->y.cbegin() + last_j, ttglyph->y.cbegin() + last_j + j);
2232         glyph->contours[i].flags.assign(ttglyph->flags.cbegin() + last_j, ttglyph->flags.cbegin() + last_j + j);
2233         glyph->contours[i].x.push_back(ttglyph->x[last_j]);
2234         glyph->contours[i].y.push_back(ttglyph->y[last_j]);
2235         glyph->contours[i].flags.push_back(ttglyph->flags[last_j]);
2236 
2237         /* Figure out if this is an inside or outside contour */
2238 
2239         glyph->contours[i].inside_flag = 0;
2240 
2241         /* Plug in the reset of the contour components into the glyph */
2242 
2243         glyph->contours[i].count = j;
2244 
2245         /*
2246          * Set last_j to point to the beginning of the next contour's coordinate
2247          * information
2248          */
2249 
2250         last_j = ttglyph->endPoints[i] + 1;
2251     }
2252 
2253     /* Show statistics about this glyph */
2254 
2255 #ifdef TTF_DEBUG
2256     Debug_Info("Number of contours: %u\n", glyph->header.numContours);
2257     Debug_Info("X extent: [%f, %f]\n",
2258         (DBL)glyph->header.xMin / (DBL)ffile->info->unitsPerEm,
2259         (DBL)glyph->header.xMax / (DBL)ffile->info->unitsPerEm);
2260 
2261     Debug_Info("Y extent: [%f, %f]\n",
2262         (DBL)glyph->header.yMin / (DBL)ffile->info->unitsPerEm,
2263         (DBL)glyph->header.yMax / (DBL)ffile->info->unitsPerEm);
2264 
2265     Debug_Info("Converted coord list(%d):\n", (int)glyph->header.numContours);
2266 
2267     for (i=0;i<(USHORT)glyph->header.numContours;i++)
2268     {
2269         for (j=0;j<=glyph->contours[i].count;j++)
2270             Debug_Info("  %c[%f, %f]\n",
2271                 (glyph->contours[i].flags[j] & ONCURVE ? '*' : ' '),
2272                 glyph->contours[i].x[j], glyph->contours[i].y[j]);
2273         Debug_Info("\n");
2274     }
2275 #endif
2276 
2277     return glyph;
2278 }
2279 
2280 /* Test to see if "point" is inside the splined polygon "points". */
Inside_Glyph(double x,double y,const GlyphStruct * glyph) const2281 bool TrueType::Inside_Glyph(double x, double y, const GlyphStruct* glyph) const
2282 {
2283     int i, j, k, n, n1, crossings;
2284     int qi, ri, qj, rj;
2285     Contour *contour;
2286     double xt[3], yt[3], roots[2];
2287     DBL *xv, *yv;
2288     double x0, x1, x2, t;
2289     double y0, y1, y2;
2290     double m, b, xc;
2291     BYTE *fv;
2292 
2293     crossings = 0;
2294 
2295     n = glyph->header.numContours;
2296 
2297     contour = glyph->contours;
2298 
2299     for (i = 0; i < n; i++)
2300     {
2301         xv = contour[i].x.data();
2302         yv = contour[i].y.data();
2303         fv = contour[i].flags.data();
2304         x0 = xv[0];
2305         y0 = yv[0];
2306         n1 = contour[i].count;
2307 
2308         for (j = 1; j <= n1; j++)
2309         {
2310             x1 = xv[j];
2311             y1 = yv[j];
2312 
2313             if (fv[j] & ONCURVE)
2314             {
2315                 /* Straight line - first set up for the next */
2316                 /* Now do the crossing test */
2317 
2318                 qi = ri = qj = rj = 0;
2319 
2320                 if (y0 == y1)
2321                     goto end_line_test;
2322 
2323                 /* if (fabs((y - y0) / (y1 - y0)) < EPSILON) goto end_line_test; */
2324 
2325                 if (y0 < y)
2326                     qi = 1;
2327 
2328                 if (y1 < y)
2329                     qj = 1;
2330 
2331                 if (qi == qj)
2332                     goto end_line_test;
2333 
2334                 if (x0 > x)
2335                     ri = 1;
2336 
2337                 if (x1 > x)
2338                     rj = 1;
2339 
2340                 if (ri & rj)
2341                 {
2342                     crossings++;
2343                     goto end_line_test;
2344                 }
2345 
2346                 if ((ri | rj) == 0)
2347                     goto end_line_test;
2348 
2349                 m = (y1 - y0) / (x1 - x0);
2350                 b = (y1 - y) - m * (x1 - x);
2351 
2352                 if ((b / m) < EPSILON)
2353                 {
2354                     crossings++;
2355                 }
2356 
2357             end_line_test:
2358                 x0 = x1;
2359                 y0 = y1;
2360             }
2361             else
2362             {
2363                 if (j == n1)
2364                 {
2365                     x2 = xv[0];
2366                     y2 = yv[0];
2367                 }
2368                 else
2369                 {
2370                     x2 = xv[j + 1];
2371                     y2 = yv[j + 1];
2372 
2373                     if (!(fv[j + 1] & ONCURVE))
2374                     {
2375                         /*
2376                          * Parabola with far end floating - readjust the far end so that it
2377                          * is on the curve.
2378                          */
2379 
2380                         x2 = 0.5 * (x1 + x2);
2381                         y2 = 0.5 * (y1 + y2);
2382                     }
2383                 }
2384 
2385                 /* only test crossing when y is in the range */
2386                 /* this should also help saving some computations */
2387                 if (((y0 < y) && (y1 < y) && (y2 < y)) ||
2388                     ((y0 > y) && (y1 > y) && (y2 > y)))
2389                     goto end_curve_test;
2390 
2391                 yt[0] = y0 - 2.0 * y1 + y2;
2392                 yt[1] = 2.0 * (y1 - y0);
2393                 yt[2] = y0 - y;
2394 
2395                 k = solve_quad(yt, roots, 0.0, 1.0);
2396 
2397                 for (ri = 0; ri < k;) {
2398                     if (roots[ri] <= EPSILON) {
2399                         /* if y actually is not in range, discard the root */
2400                         if (((y <= y0) && (y < y1)) || ((y >= y0) && (y > y1))) {
2401                             k--;
2402                             if (k > ri)
2403                                 roots[ri] = roots[ri+1];
2404                             continue;
2405                         }
2406                     }
2407                     else if (roots[ri] >= (1.0 - EPSILON)) {
2408                         /* if y actually is not in range, discard the root */
2409                         if (((y < y2) && (y < y1)) || ((y > y2) && (y > y1))) {
2410                             k--;
2411                             if (k > ri)
2412                                 roots[ri] = roots[ri+1];
2413                             continue;
2414                         }
2415                     }
2416 
2417                     ri++;
2418                 }
2419 
2420                 if (k > 0)
2421                 {
2422                     xt[0] = x0 - 2.0 * x1 + x2;
2423                     xt[1] = 2.0 * (x1 - x0);
2424                     xt[2] = x0;
2425 
2426                     t = roots[0];
2427 
2428                     xc = (xt[0] * t + xt[1]) * t + xt[2];
2429 
2430                     if (xc > x)
2431                         crossings++;
2432 
2433                     if (k > 1)
2434                     {
2435                         t = roots[1];
2436                         xc = (xt[0] * t + xt[1]) * t + xt[2];
2437 
2438                         if (xc > x)
2439                             crossings++;
2440                     }
2441                 }
2442 
2443 end_curve_test:
2444 
2445                 x0 = x2;
2446 
2447                 y0 = y2;
2448             }
2449         }
2450     }
2451 
2452     return ((crossings & 1) != 0);
2453 }
2454 
2455 
solve_quad(double * x,double * y,double mindist,DBL maxdist) const2456 int TrueType::solve_quad(double *x, double *y, double mindist, DBL maxdist) const
2457 {
2458     double d, t, a, b, c, q;
2459 
2460     a = x[0];
2461     b = -x[1];
2462     c = x[2];
2463 
2464     if (fabs(a) < COEFF_LIMIT)
2465     {
2466         if (fabs(b) < COEFF_LIMIT)
2467             return 0;
2468 
2469         q = c / b;
2470 
2471         if (q >= mindist && q <= maxdist)
2472         {
2473             y[0] = q;
2474             return 1;
2475         }
2476         else
2477             return 0;
2478     }
2479 
2480     d = b * b - 4.0 * a * c;
2481 
2482     if (d < EPSILON)
2483         return 0;
2484 
2485     d = sqrt(d);
2486     t = 2.0 * a;
2487     q = (b + d) / t;
2488 
2489     if (q >= mindist && q <= maxdist)
2490     {
2491         y[0] = q;
2492         q = (b - d) / t;
2493 
2494         if (q >= mindist && q <= maxdist)
2495         {
2496             y[1] = q;
2497             return 2;
2498         }
2499 
2500         return 1;
2501     }
2502 
2503     q = (b - d) / t;
2504 
2505     if (q >= mindist && q <= maxdist)
2506     {
2507         y[0] = q;
2508         return 1;
2509     }
2510 
2511     return 0;
2512 }
2513 
2514 /*
2515  * Returns the distance to z = 0 in t0, and the distance to z = 1 in t1.
2516  * These distances are to the the bottom and top surfaces of the glyph.
2517  * The distances are set to -1 if there is no hit.
2518  */
GetZeroOneHits(const GlyphStruct * glyph,const Vector3d & P,const Vector3d & D,DBL glyph_depth,double * t0,double * t1) const2519 void TrueType::GetZeroOneHits(const GlyphStruct* glyph, const Vector3d& P, const Vector3d& D, DBL glyph_depth, double *t0, double *t1) const
2520 {
2521     double x0, y0, t;
2522 
2523     *t0 = -1.0;
2524     *t1 = -1.0;
2525 
2526     /* Are we parallel to the x-y plane? */
2527 
2528     if (fabs(D[Z]) < EPSILON)
2529         return;
2530 
2531     /* Solve: P[Y] + t * D[Y] = 0 */
2532 
2533     t = -P[Z] / D[Z];
2534 
2535     x0 = P[X] + t * D[X];
2536     y0 = P[Y] + t * D[Y];
2537 
2538     if (Inside_Glyph(x0, y0, glyph))
2539         *t0 = t;
2540 
2541     /* Solve: P[Y] + t * D[Y] = glyph_depth */
2542 
2543     t += (glyph_depth / D[Z]);
2544 
2545     x0 = P[X] + t * D[X];
2546     y0 = P[Y] + t * D[Y];
2547 
2548     if (Inside_Glyph(x0, y0, glyph))
2549         *t1 = t;
2550 }
2551 
2552 /*
2553  * Solving for a linear sweep of a non-linear curve can be performed by
2554  * projecting the ray onto the x-y plane, giving a parametric equation for the
2555  * ray as:
2556  *
2557  * x = x0 + x1 t, y = y0 + y1 t
2558  *
2559  * Eliminating t from the above gives the implicit equation:
2560  *
2561  * y1 x - x1 y - (x0 y1 - y0 x1) = 0.
2562  *
2563  * Substituting a parametric equation for x and y gives:
2564  *
2565  * y1 x(s) - x1 y(s) - (x0 y1 - y0 x1) = 0.
2566  *
2567  * which can be written as
2568  *
2569  * a x(s) + b y(s) + c = 0,
2570  *
2571  * where a = y1, b = -x1, c = (y0 x1 - x0 y1).
2572  *
2573  * For piecewise quadratics, the parametric equations will have the forms:
2574  *
2575  * x(s) = (1-s)^2 P0(x) + 2 s (1 - s) P1(x) + s^2 P2(x) y(s) = (1-s)^2 P0(y) + 2 s
2576  * (1 - s) P1(y) + s^2 P2(y)
2577  *
2578  * where P0 is the first defining vertex of the spline, P1 is the second, P2 is
2579  * the third.  Using the substitutions:
2580  *
2581  * xt2 = x0 - 2 x1 + x2, xt1 = 2 * (x1 - x0), xt0 = x0; yt2 = y0 - 2 y1 + y2, yt1
2582  * = 2 * (y1 - y0), yt0 = y0;
2583  *
2584  * the equations can be written as:
2585  *
2586  * x(s) = xt2 s^2 + xt1 s + xt0, y(s) = yt2 s^2 + yt1 s + yt0.
2587  *
2588  * Substituting and multiplying out gives the following equation in s:
2589  *
2590  * s^2 * (a*xt2 + b*yt2) + s   * (a*xt1 + b*yt1) + c + a*xt0 + b*yt0
2591  *
2592  * This is then solved using the quadratic formula.  Any solutions of s that are
2593  * between 0 and 1 (inclusive) are valid solutions.
2594  */
GlyphIntersect(const Vector3d & P,const Vector3d & D,const GlyphStruct * glyph,DBL glyph_depth,const BasicRay & ray,IStack & Depth_Stack,TraceThreadData * Thread)2595 bool TrueType::GlyphIntersect(const Vector3d& P, const Vector3d& D, const GlyphStruct* glyph, DBL glyph_depth, const BasicRay& ray, IStack& Depth_Stack, TraceThreadData *Thread)
2596 {
2597     Contour *contour;
2598     int i, j, k, l, n, m;
2599     bool Flag = false;
2600     Vector3d N, IPoint;
2601     DBL Depth;
2602     double x0, x1, y0, y1, x2, y2, t, t0, t1, z;
2603     double xt0, xt1, xt2, yt0, yt1, yt2;
2604     double a, b, c, d0, d1, C[3], S[2];
2605     DBL *xv, *yv;
2606     BYTE *fv;
2607     int dirflag = 0;
2608 
2609     /*
2610      * First thing to do is to get any hits at z = 0 and z = 1 (which are the
2611      * bottom and top surfaces of the glyph.
2612      */
2613 
2614     GetZeroOneHits(glyph, P, D, glyph_depth, &t0, &t1);
2615 
2616     if (t0 > 0.0)
2617     {
2618         Depth = t0 /* / len */;
2619         IPoint = ray.Evaluate(Depth);
2620 
2621         if (Depth > TTF_Tolerance && (Clip.empty() || Point_In_Clip(IPoint, Clip, Thread)))
2622         {
2623             N = Vector3d(0.0, 0.0, -1.0);
2624             MTransNormal(N, N, Trans);
2625             N.normalize();
2626             Depth_Stack->push(Intersection(Depth, IPoint, N, this));
2627             Flag = true;
2628         }
2629     }
2630 
2631     if (t1 > 0.0)
2632     {
2633         Depth = t1 /* / len */;
2634         IPoint = ray.Evaluate(Depth);
2635 
2636         if (Depth > TTF_Tolerance && (Clip.empty() || Point_In_Clip(IPoint, Clip, Thread)))
2637         {
2638             N = Vector3d(0.0, 0.0, 1.0);
2639             MTransNormal(N, N, Trans);
2640             N.normalize();
2641             Depth_Stack->push(Intersection(Depth, IPoint, N, this));
2642             Flag = true;
2643         }
2644     }
2645 
2646     /* Simple test to see if we can just toss this ray */
2647 
2648     if (fabs(D[X]) < EPSILON)
2649     {
2650         if (fabs(D[Y]) < EPSILON)
2651         {
2652             /*
2653              * This means the ray is moving parallel to the walls of the sweep
2654              * surface
2655              */
2656             return Flag;
2657         }
2658         else
2659         {
2660             dirflag = 0;
2661         }
2662     }
2663     else
2664     {
2665         dirflag = 1;
2666     }
2667 
2668     /*
2669      * Now walk through the glyph, looking for places where the ray hits the
2670      * walls
2671      */
2672 
2673     a = D[Y];
2674     b = -D[X];
2675     c = (P[Y] * D[X] - P[X] * D[Y]);
2676 
2677     n = glyph->header.numContours;
2678 
2679     for (i = 0, contour = glyph->contours; i < n; i++, contour++)
2680     {
2681         xv = contour->x.data();
2682         yv = contour->y.data();
2683         fv = contour->flags.data();
2684         x0 = xv[0];
2685         y0 = yv[0];
2686         m = contour->count;
2687 
2688         for (j = 1; j <= m; j++)
2689         {
2690             x1 = xv[j];
2691             y1 = yv[j];
2692 
2693             if (fv[j] & ONCURVE)
2694             {
2695                 /* Straight line */
2696                 d0 = (x1 - x0);
2697                 d1 = (y1 - y0);
2698 
2699                 t0 = d1 * D[X] - d0 * D[Y];
2700 
2701                 if (fabs(t0) < EPSILON)
2702                     /* No possible intersection */
2703                     goto end_line_test;
2704 
2705                 t = (D[X] * (P[Y] - y0) - D[Y] * (P[X] - x0)) / t0;
2706 
2707                 if (t < 0.0 || t > 1.0)
2708                     goto end_line_test;
2709 
2710                 if (dirflag)
2711                     t = ((x0 + t * d0) - P[X]) / D[X];
2712                 else
2713                     t = ((y0 + t * d1) - P[Y]) / D[Y];
2714 
2715                 z = P[Z] + t * D[Z];
2716 
2717                 Depth = t /* / len */;
2718 
2719                 if (z >= 0 && z <= glyph_depth && Depth > TTF_Tolerance)
2720                 {
2721                     IPoint = ray.Evaluate(Depth);
2722 
2723                     if (Clip.empty() || Point_In_Clip(IPoint, Clip, Thread))
2724                     {
2725                         N = Vector3d(-d1, d0, 0.0);
2726                         MTransNormal(N, N, Trans);
2727                         N.normalize();
2728                         Depth_Stack->push(Intersection(Depth, IPoint, N, this));
2729                         Flag = true;
2730                     }
2731                 }
2732             end_line_test:
2733                 x0 = x1;
2734                 y0 = y1;
2735             }
2736             else
2737             {
2738                 if (j == m)
2739                 {
2740                     x2 = xv[0];
2741                     y2 = yv[0];
2742                 }
2743                 else
2744                 {
2745                     x2 = xv[j + 1];
2746                     y2 = yv[j + 1];
2747 
2748                     if (!(fv[j + 1] & ONCURVE))
2749                     {
2750 
2751                         /*
2752                          * Parabola with far end DBLing - readjust the far end so that it
2753                          * is on the curve.  (In the correct place too.)
2754                          */
2755 
2756                         x2 = 0.5 * (x1 + x2);
2757                         y2 = 0.5 * (y1 + y2);
2758                     }
2759                 }
2760 
2761                 /* Make the interpolating quadrics */
2762 
2763                 xt2 = x0 - 2.0 * x1 + x2;
2764                 xt1 = 2.0 * (x1 - x0);
2765                 xt0 = x0;
2766                 yt2 = y0 - 2.0 * y1 + y2;
2767                 yt1 = 2.0 * (y1 - y0);
2768                 yt0 = y0;
2769 
2770                 C[0] = a * xt2 + b * yt2;
2771                 C[1] = a * xt1 + b * yt1;
2772                 C[2] = a * xt0 + b * yt0 + c;
2773 
2774                 k = solve_quad(C, S, 0.0, 1.0);
2775 
2776                 for (l = 0; l < k; l++)
2777                 {
2778                     if (dirflag)
2779                         t = ((S[l] * S[l] * xt2 + S[l] * xt1 + xt0) - P[X]) / D[X];
2780                     else
2781                         t = ((S[l] * S[l] * yt2 + S[l] * yt1 + yt0) - P[Y]) / D[Y];
2782 
2783                     /*
2784                      * If the intersection with this wall is between 0 and glyph_depth
2785                      * along the z-axis, then it is a valid hit.
2786                      */
2787 
2788                     z = P[Z] + t * D[Z];
2789 
2790                     Depth = t /* / len */;
2791 
2792                     if (z >= 0 && z <= glyph_depth && Depth > TTF_Tolerance)
2793                     {
2794                         IPoint = ray.Evaluate(Depth);
2795 
2796                         if (Clip.empty() || Point_In_Clip(IPoint, Clip, Thread))
2797                         {
2798                             N = Vector3d(-2.0 * yt2 * S[l] - yt1, 2.0 * xt2 * S[l] + xt1, 0.0);
2799                             MTransNormal(N, N, Trans);
2800                             N.normalize();
2801                             Depth_Stack->push(Intersection(Depth, IPoint, N, this));
2802                             Flag = true;
2803                         }
2804                     }
2805                 }
2806 
2807                 x0 = x2;
2808                 y0 = y2;
2809             }
2810         }
2811     }
2812 
2813     return Flag;
2814 }
2815 
All_Intersections(const Ray & ray,IStack & Depth_Stack,TraceThreadData * Thread)2816 bool TrueType::All_Intersections(const Ray& ray, IStack& Depth_Stack, TraceThreadData *Thread)
2817 {
2818     Vector3d P, D;
2819 
2820     Thread->Stats()[Ray_TTF_Tests]++;
2821 
2822     /* Transform the point into the glyph's space */
2823 
2824     MInvTransPoint(P, ray.Origin, Trans);
2825     MInvTransDirection(D, ray.Direction, Trans);
2826 
2827     /* Tweak the ray to try to avoid pathalogical intersections */
2828 /*  DBL len;
2829 
2830     D[0] *= 1.0000013147;
2831     D[1] *= 1.0000022741;
2832     D[2] *= 1.0000017011;
2833 
2834     D.normalize();
2835 */
2836 
2837     if (GlyphIntersect(P, D, glyph, depth, ray, Depth_Stack, Thread)) /* tw */
2838     {
2839         Thread->Stats()[Ray_TTF_Tests_Succeeded]++;
2840         return true;
2841     }
2842 
2843     return false;
2844 }
2845 
Inside(const Vector3d & IPoint,TraceThreadData * Thread) const2846 bool TrueType::Inside(const Vector3d& IPoint, TraceThreadData *Thread) const
2847 {
2848     Vector3d New_Point;
2849 
2850     /* Transform the point into font space */
2851 
2852     MInvTransPoint(New_Point, IPoint, Trans);
2853 
2854     if (New_Point[Z] >= 0.0 && New_Point[Z] <= depth &&
2855         Inside_Glyph(New_Point[X], New_Point[Y], glyph))
2856         return (!Test_Flag(this, INVERTED_FLAG));
2857     else
2858         return (Test_Flag(this, INVERTED_FLAG));
2859 }
2860 
Normal(Vector3d & Result,Intersection * Inter,TraceThreadData * Thread) const2861 void TrueType::Normal(Vector3d& Result, Intersection *Inter, TraceThreadData *Thread) const
2862 {
2863     /* Use precomputed normal. [ARE 11/94] */
2864 
2865     Result = Inter->INormal;
2866 }
2867 
Copy()2868 ObjectPtr TrueType::Copy()
2869 {
2870     TrueType *New = new TrueType();
2871     Destroy_Transform(New->Trans);
2872     *New = *this;
2873     New->Trans = Copy_Transform(Trans);
2874     New->glyph = glyph; // TODO - How can this work correctly? [trf]
2875     return (New);
2876 }
2877 
Translate(const Vector3d &,const TRANSFORM * tr)2878 void TrueType::Translate(const Vector3d& /*Vector*/, const TRANSFORM *tr)
2879 {
2880     Transform(tr);
2881 }
2882 
Rotate(const Vector3d &,const TRANSFORM * tr)2883 void TrueType::Rotate(const Vector3d& /*Vector*/, const TRANSFORM *tr)
2884 {
2885     Transform(tr);
2886 }
2887 
Scale(const Vector3d &,const TRANSFORM * tr)2888 void TrueType::Scale(const Vector3d& /*Vector*/, const TRANSFORM *tr)
2889 {
2890     Transform(tr);
2891 }
2892 
Transform(const TRANSFORM * tr)2893 void TrueType::Transform(const TRANSFORM *tr)
2894 {
2895     Compose_Transforms(Trans, tr);
2896 
2897     /* Calculate the bounds */
2898 
2899     Compute_BBox();
2900 }
2901 
TrueType()2902 TrueType::TrueType() : ObjectBase(TTF_OBJECT)
2903 {
2904     /* Initialize TTF specific information */
2905 
2906     Trans = Create_Transform();
2907 
2908     glyph = nullptr;
2909     depth = 1.0;
2910 
2911     /* Default bounds */
2912     Make_BBox(BBox, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0);
2913 }
2914 
~TrueType()2915 TrueType::~TrueType()
2916 {}
2917 
2918 
2919 
2920 /*****************************************************************************
2921 *
2922 * FUNCTION
2923 *
2924 *   Compute_TTF_BBox
2925 *
2926 * INPUT
2927 *
2928 *   ttf - ttf
2929 *
2930 * OUTPUT
2931 *
2932 *   ttf
2933 *
2934 * RETURNS
2935 *
2936 * AUTHOR
2937 *
2938 *   Dieter Bayer, August 1994
2939 *
2940 * DESCRIPTION
2941 *
2942 *   Calculate the bounding box of a true type font.
2943 *
2944 * CHANGES
2945 *
2946 *   -
2947 *
2948 ******************************************************************************/
Compute_BBox()2949 void TrueType::Compute_BBox()
2950 {
2951     DBL funit_size, xMin, yMin, zMin, xMax, yMax, zMax;
2952 
2953     funit_size = 1.0 / (DBL)(glyph->unitsPerEm);
2954 
2955     xMin = (DBL)glyph->header.xMin * funit_size;
2956     yMin = (DBL)glyph->header.yMin * funit_size;
2957     zMin = -TTF_Tolerance;
2958 
2959     xMax = (DBL)glyph->header.xMax * funit_size;
2960     yMax = (DBL)glyph->header.yMax * funit_size;
2961     zMax = depth + TTF_Tolerance;
2962 
2963     Make_BBox(BBox, xMin, yMin, zMin, xMax - xMin, yMax - yMin, zMax - zMin);
2964 
2965 #ifdef TTF_DEBUG
2966     Debug_Info("Bounds: <%g,%g,%g> -> <%g,%g,%g>\n",
2967                ttf->BBox.lowerLeft[0],
2968                ttf->BBox.lowerLeft[1],
2969                ttf->BBox.lowerLeft[2],
2970                ttf->BBox.size[0],
2971                ttf->BBox.size[1],
2972                ttf->BBox.size[2]);
2973 #endif
2974 
2975     /* Apply the transformation to the bounding box */
2976 
2977     Recompute_BBox(&BBox, Trans);
2978 }
2979 
2980 
TrueTypeFont(const UCS2String & fn,IStream * fp,StringEncoding te)2981 TrueTypeFont::TrueTypeFont(const UCS2String& fn, IStream* fp, StringEncoding te) :
2982     filename(fn),
2983     fp(fp),
2984     textEncoding(te),
2985     info(nullptr)
2986 {
2987     ProcessFontFile(this);
2988 }
2989 
~TrueTypeFont()2990 TrueTypeFont::~TrueTypeFont()
2991 {
2992     if (fp != nullptr)
2993         delete fp;
2994 
2995     if (info != nullptr)
2996         delete info;
2997 }
2998 
TrueTypeInfo()2999 TrueTypeInfo::TrueTypeInfo() :
3000     cmap_table_offset(0),
3001     glyf_table_offset(0),
3002     numGlyphs(0),
3003     unitsPerEm(0),
3004     indexToLocFormat(0),
3005     loca_table(nullptr),
3006     numberOfHMetrics(0),
3007     hmtx_table(nullptr),
3008     glyphIDoffset(0),
3009     segCount(0),
3010     searchRange(0),
3011     entrySelector(0),
3012     rangeShift(0),
3013     startCount(nullptr),
3014     endCount(nullptr),
3015     idDelta(nullptr),
3016     idRangeOffset(nullptr)
3017 {
3018     for (int i = 0; i < 4; i ++)
3019     {
3020         platformID[i] = 0;
3021         specificID[i] = 0;
3022     }
3023 
3024     kerning_tables.nTables = 0;
3025     kerning_tables.tables = nullptr;
3026 }
3027 
~TrueTypeInfo()3028 TrueTypeInfo::~TrueTypeInfo()
3029 {
3030     if (loca_table != nullptr)
3031         delete[] loca_table;
3032 
3033     for (GlyphPtrMap::iterator iGlyph = glyphsByIndex.begin(); iGlyph != glyphsByIndex.end(); ++iGlyph)
3034     {
3035         if ((*iGlyph).second->contours != nullptr)
3036             delete[] (*iGlyph).second->contours;
3037         delete (*iGlyph).second;
3038     }
3039 
3040     if (kerning_tables.tables != nullptr)
3041     {
3042         for (int i = 0; i < kerning_tables.nTables; i++)
3043         {
3044             if (kerning_tables.tables[i].kern_pairs != nullptr)
3045                 delete[] kerning_tables.tables[i].kern_pairs;
3046         }
3047 
3048         delete[] kerning_tables.tables;
3049     }
3050 
3051     if (hmtx_table != nullptr)
3052         delete[] hmtx_table;
3053 
3054     if (endCount != nullptr)
3055         delete[] endCount;
3056 
3057     if (startCount != nullptr)
3058         delete[] startCount;
3059 
3060     if (idDelta != nullptr)
3061         delete[] idDelta;
3062 
3063     if (idRangeOffset != nullptr)
3064         delete[] idRangeOffset;
3065 }
3066 
3067 }
3068 
3069