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