1 | // SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later |
2 | // Copyright 2010, SIL International, All rights reserved. |
3 | |
4 | /* |
5 | Responsibility: Alan Ward |
6 | Last reviewed: Not yet. |
7 | |
8 | Description |
9 | Implements the methods for TtfUtil class. This file should remain portable to any C++ |
10 | environment by only using standard C++ and the TTF structurs defined in Tt.h. |
11 | */ |
12 | |
13 | |
14 | /*********************************************************************************************** |
15 | Include files |
16 | ***********************************************************************************************/ |
17 | // Language headers |
18 | //#include <algorithm> |
19 | #include <cassert> |
20 | #include <cstddef> |
21 | #include <cstring> |
22 | #include <climits> |
23 | #include <cwchar> |
24 | //#include <stdexcept> |
25 | // Platform headers |
26 | // Module headers |
27 | #include "inc/TtfUtil.h" |
28 | #include "inc/TtfTypes.h" |
29 | #include "inc/Endian.h" |
30 | |
31 | /*********************************************************************************************** |
32 | Forward declarations |
33 | ***********************************************************************************************/ |
34 | |
35 | /*********************************************************************************************** |
36 | Local Constants and static variables |
37 | ***********************************************************************************************/ |
38 | namespace |
39 | { |
40 | #ifdef ALL_TTFUTILS |
41 | // max number of components allowed in composite glyphs |
42 | const int kMaxGlyphComponents = 8; |
43 | #endif |
44 | |
45 | template <int R, typename T> |
46 | inline float fixed_to_float(const T f) { |
47 | return float(f)/float(2^R); |
48 | } |
49 | |
50 | /*---------------------------------------------------------------------------------------------- |
51 | Table of standard Postscript glyph names. From Martin Hosken. Disagress with ttfdump.exe |
52 | ---------------------------------------------------------------------------------------------*/ |
53 | #ifdef ALL_TTFUTILS |
54 | const int kcPostNames = 258; |
55 | |
56 | const char * rgPostName[kcPostNames] = { |
57 | ".notdef" , ".null" , "nonmarkingreturn" , "space" , "exclam" , "quotedbl" , "numbersign" , |
58 | "dollar" , "percent" , "ampersand" , "quotesingle" , "parenleft" , |
59 | "parenright" , "asterisk" , "plus" , "comma" , "hyphen" , "period" , "slash" , |
60 | "zero" , "one" , "two" , "three" , "four" , "five" , "six" , "seven" , "eight" , |
61 | "nine" , "colon" , "semicolon" , "less" , "equal" , "greater" , "question" , |
62 | "at" , "A" , "B" , "C" , "D" , "E" , "F" , "G" , "H" , "I" , "J" , "K" , "L" , "M" , |
63 | "N" , "O" , "P" , "Q" , "R" , "S" , "T" , "U" , "V" , "W" , "X" , "Y" , "Z" , |
64 | "bracketleft" , "backslash" , "bracketright" , "asciicircum" , |
65 | "underscore" , "grave" , "a" , "b" , "c" , "d" , "e" , "f" , "g" , "h" , "i" , |
66 | "j" , "k" , "l" , "m" , "n" , "o" , "p" , "q" , "r" , "s" , "t" , "u" , "v" , "w" , |
67 | "x" , "y" , "z" , "braceleft" , "bar" , "braceright" , "asciitilde" , |
68 | "Adieresis" , "Aring" , "Ccedilla" , "Eacute" , "Ntilde" , "Odieresis" , |
69 | "Udieresis" , "aacute" , "agrave" , "acircumflex" , "adieresis" , "atilde" , |
70 | "aring" , "ccedilla" , "eacute" , "egrave" , "ecircumflex" , "edieresis" , |
71 | "iacute" , "igrave" , "icircumflex" , "idieresis" , "ntilde" , "oacute" , |
72 | "ograve" , "ocircumflex" , "odieresis" , "otilde" , "uacute" , "ugrave" , |
73 | "ucircumflex" , "udieresis" , "dagger" , "degree" , "cent" , "sterling" , |
74 | "section" , "bullet" , "paragraph" , "germandbls" , "registered" , |
75 | "copyright" , "trademark" , "acute" , "dieresis" , "notequal" , "AE" , |
76 | "Oslash" , "infinity" , "plusminus" , "lessequal" , "greaterequal" , "yen" , |
77 | "mu" , "partialdiff" , "summation" , "product" , "pi" , "integral" , |
78 | "ordfeminine" , "ordmasculine" , "Omega" , "ae" , "oslash" , "questiondown" , |
79 | "exclamdown" , "logicalnot" , "radical" , "florin" , "approxequal" , |
80 | "Delta" , "guillemotleft" , "guillemotright" , "ellipsis" , "nonbreakingspace" , |
81 | "Agrave" , "Atilde" , "Otilde" , "OE" , "oe" , "endash" , "emdash" , |
82 | "quotedblleft" , "quotedblright" , "quoteleft" , "quoteright" , "divide" , |
83 | "lozenge" , "ydieresis" , "Ydieresis" , "fraction" , "currency" , |
84 | "guilsinglleft" , "guilsinglright" , "fi" , "fl" , "daggerdbl" , "periodcentered" , |
85 | "quotesinglbase" , "quotedblbase" , "perthousand" , "Acircumflex" , |
86 | "Ecircumflex" , "Aacute" , "Edieresis" , "Egrave" , "Iacute" , |
87 | "Icircumflex" , "Idieresis" , "Igrave" , "Oacute" , "Ocircumflex" , |
88 | "apple" , "Ograve" , "Uacute" , "Ucircumflex" , "Ugrave" , "dotlessi" , |
89 | "circumflex" , "tilde" , "macron" , "breve" , "dotaccent" , "ring" , |
90 | "cedilla" , "hungarumlaut" , "ogonek" , "caron" , "Lslash" , "lslash" , |
91 | "Scaron" , "scaron" , "Zcaron" , "zcaron" , "brokenbar" , "Eth" , "eth" , |
92 | "Yacute" , "yacute" , "Thorn" , "thorn" , "minus" , "multiply" , |
93 | "onesuperior" , "twosuperior" , "threesuperior" , "onehalf" , "onequarter" , |
94 | "threequarters" , "franc" , "Gbreve" , "gbreve" , "Idotaccent" , "Scedilla" , |
95 | "scedilla" , "Cacute" , "cacute" , "Ccaron" , "ccaron" , |
96 | "dcroat" }; |
97 | #endif |
98 | |
99 | } // end of namespace |
100 | |
101 | /*********************************************************************************************** |
102 | Methods |
103 | ***********************************************************************************************/ |
104 | |
105 | /* Note on error processing: The code guards against bad glyph ids being used to look up data |
106 | in open ended tables (loca, hmtx). If the glyph id comes from a cmap this shouldn't happen |
107 | but it seems prudent to check for user errors here. The code does assume that data obtained |
108 | from the TTF file is valid otherwise (though the CheckTable method seeks to check for |
109 | obvious problems that might accompany a change in table versions). For example an invalid |
110 | offset in the loca table which could exceed the size of the glyf table is NOT trapped. |
111 | Likewise if numberOf_LongHorMetrics in the hhea table is wrong, this will NOT be trapped, |
112 | which could cause a lookup in the hmtx table to exceed the table length. Of course, TTF tables |
113 | that are completely corrupt will cause unpredictable results. */ |
114 | |
115 | /* Note on composite glyphs: Glyphs that have components that are themselves composites |
116 | are not supported. IsDeepComposite can be used to test for this. False is returned from many |
117 | of the methods in this cases. It is unclear how to build composite glyphs in some cases, |
118 | so this code represents my best guess until test cases can be found. See notes on the high- |
119 | level GlyfPoints method. */ |
120 | namespace graphite2 |
121 | { |
122 | namespace TtfUtil |
123 | { |
124 | |
125 | |
126 | /*---------------------------------------------------------------------------------------------- |
127 | Get offset and size of the offset table needed to find table directory. |
128 | Return true if success, false otherwise. |
129 | lSize excludes any table directory entries. |
130 | ----------------------------------------------------------------------------------------------*/ |
131 | bool (size_t & lOffset, size_t & lSize) |
132 | { |
133 | lOffset = 0; |
134 | lSize = offsetof(Sfnt::OffsetSubTable, table_directory); |
135 | assert(sizeof(uint32) + 4*sizeof (uint16) == lSize); |
136 | return true; |
137 | } |
138 | |
139 | /*---------------------------------------------------------------------------------------------- |
140 | Check the offset table for expected data. |
141 | Return true if success, false otherwise. |
142 | ----------------------------------------------------------------------------------------------*/ |
143 | bool (const void * pHdr) |
144 | { |
145 | const Sfnt::OffsetSubTable * pOffsetTable |
146 | = reinterpret_cast<const Sfnt::OffsetSubTable *>(pHdr); |
147 | |
148 | return pHdr && be::swap(pOffsetTable->scaler_type) == Sfnt::OffsetSubTable::TrueTypeWin; |
149 | } |
150 | |
151 | /*---------------------------------------------------------------------------------------------- |
152 | Get offset and size of the table directory. |
153 | Return true if successful, false otherwise. |
154 | ----------------------------------------------------------------------------------------------*/ |
155 | bool GetTableDirInfo(const void * pHdr, size_t & lOffset, size_t & lSize) |
156 | { |
157 | const Sfnt::OffsetSubTable * pOffsetTable |
158 | = reinterpret_cast<const Sfnt::OffsetSubTable *>(pHdr); |
159 | |
160 | lOffset = offsetof(Sfnt::OffsetSubTable, table_directory); |
161 | lSize = be::swap(pOffsetTable->num_tables) |
162 | * sizeof(Sfnt::OffsetSubTable::Entry); |
163 | |
164 | return true; |
165 | } |
166 | |
167 | |
168 | /*---------------------------------------------------------------------------------------------- |
169 | Get offset and size of the specified table. |
170 | Return true if successful, false otherwise. On false, offset and size will be 0. |
171 | ----------------------------------------------------------------------------------------------*/ |
172 | bool GetTableInfo(const Tag TableTag, const void * pHdr, const void * pTableDir, |
173 | size_t & lOffset, size_t & lSize) |
174 | { |
175 | const Sfnt::OffsetSubTable * pOffsetTable |
176 | = reinterpret_cast<const Sfnt::OffsetSubTable *>(pHdr); |
177 | const size_t num_tables = be::swap(pOffsetTable->num_tables); |
178 | const Sfnt::OffsetSubTable::Entry |
179 | * entry_itr = reinterpret_cast<const Sfnt::OffsetSubTable::Entry *>( |
180 | pTableDir), |
181 | * const dir_end = entry_itr + num_tables; |
182 | |
183 | if (num_tables > 40) |
184 | return false; |
185 | |
186 | for (;entry_itr != dir_end; ++entry_itr) // 40 - safe guard |
187 | { |
188 | if (be::swap(entry_itr->tag) == TableTag) |
189 | { |
190 | lOffset = be::swap(entry_itr->offset); |
191 | lSize = be::swap(entry_itr->length); |
192 | return true; |
193 | } |
194 | } |
195 | |
196 | return false; |
197 | } |
198 | |
199 | /*---------------------------------------------------------------------------------------------- |
200 | Check the specified table. Tests depend on the table type. |
201 | Return true if successful, false otherwise. |
202 | ----------------------------------------------------------------------------------------------*/ |
203 | bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize) |
204 | { |
205 | using namespace Sfnt; |
206 | |
207 | if (pTable == 0 || lTableSize < 4) return false; |
208 | |
209 | switch(TableId) |
210 | { |
211 | case Tag::cmap: // cmap |
212 | { |
213 | const Sfnt::CharacterCodeMap * const pCmap |
214 | = reinterpret_cast<const Sfnt::CharacterCodeMap *>(pTable); |
215 | if (lTableSize < sizeof(Sfnt::CharacterCodeMap)) |
216 | return false; |
217 | return be::swap(pCmap->version) == 0; |
218 | } |
219 | |
220 | case Tag::head: // head |
221 | { |
222 | const Sfnt::FontHeader * const pHead |
223 | = reinterpret_cast<const Sfnt::FontHeader *>(pTable); |
224 | if (lTableSize < sizeof(Sfnt::FontHeader)) |
225 | return false; |
226 | bool r = be::swap(pHead->version) == OneFix |
227 | && be::swap(pHead->magic_number) == FontHeader::MagicNumber |
228 | && be::swap(pHead->glyph_data_format) |
229 | == FontHeader::GlypDataFormat |
230 | && (be::swap(pHead->index_to_loc_format) |
231 | == FontHeader::ShortIndexLocFormat |
232 | || be::swap(pHead->index_to_loc_format) |
233 | == FontHeader::LongIndexLocFormat) |
234 | && sizeof(FontHeader) <= lTableSize; |
235 | return r; |
236 | } |
237 | |
238 | case Tag::post: // post |
239 | { |
240 | const Sfnt::PostScriptGlyphName * const pPost |
241 | = reinterpret_cast<const Sfnt::PostScriptGlyphName *>(pTable); |
242 | if (lTableSize < sizeof(Sfnt::PostScriptGlyphName)) |
243 | return false; |
244 | const fixed format = be::swap(pPost->format); |
245 | bool r = format == PostScriptGlyphName::Format1 |
246 | || format == PostScriptGlyphName::Format2 |
247 | || format == PostScriptGlyphName::Format3 |
248 | || format == PostScriptGlyphName::Format25; |
249 | return r; |
250 | } |
251 | |
252 | case Tag::hhea: // hhea |
253 | { |
254 | const Sfnt::HorizontalHeader * pHhea = |
255 | reinterpret_cast<const Sfnt::HorizontalHeader *>(pTable); |
256 | if (lTableSize < sizeof(Sfnt::HorizontalHeader)) |
257 | return false; |
258 | bool r = be::swap(pHhea->version) == OneFix |
259 | && be::swap(pHhea->metric_data_format) == 0 |
260 | && sizeof (Sfnt::HorizontalHeader) <= lTableSize; |
261 | return r; |
262 | } |
263 | |
264 | case Tag::maxp: // maxp |
265 | { |
266 | const Sfnt::MaximumProfile * pMaxp = |
267 | reinterpret_cast<const Sfnt::MaximumProfile *>(pTable); |
268 | if (lTableSize < sizeof(Sfnt::MaximumProfile)) |
269 | return false; |
270 | bool r = be::swap(pMaxp->version) == OneFix |
271 | && sizeof(Sfnt::MaximumProfile) <= lTableSize; |
272 | return r; |
273 | } |
274 | |
275 | case Tag::OS_2: // OS/2 |
276 | { |
277 | const Sfnt::Compatibility * pOs2 |
278 | = reinterpret_cast<const Sfnt::Compatibility *>(pTable); |
279 | if (be::swap(pOs2->version) == 0) |
280 | { // OS/2 table version 1 size |
281 | // if (sizeof(Sfnt::Compatibility) |
282 | // - sizeof(uint32)*2 - sizeof(int16)*2 |
283 | // - sizeof(uint16)*3 <= lTableSize) |
284 | if (sizeof(Sfnt::Compatibility0) <= lTableSize) |
285 | return true; |
286 | } |
287 | else if (be::swap(pOs2->version) == 1) |
288 | { // OS/2 table version 2 size |
289 | // if (sizeof(Sfnt::Compatibility) |
290 | // - sizeof(int16) *2 |
291 | // - sizeof(uint16)*3 <= lTableSize) |
292 | if (sizeof(Sfnt::Compatibility1) <= lTableSize) |
293 | return true; |
294 | } |
295 | else if (be::swap(pOs2->version) == 2) |
296 | { // OS/2 table version 3 size |
297 | if (sizeof(Sfnt::Compatibility2) <= lTableSize) |
298 | return true; |
299 | } |
300 | else if (be::swap(pOs2->version) == 3 || be::swap(pOs2->version) == 4) |
301 | { // OS/2 table version 4 size - version 4 changed the meaning of some fields which we don't use |
302 | if (sizeof(Sfnt::Compatibility3) <= lTableSize) |
303 | return true; |
304 | } |
305 | else |
306 | return false; |
307 | break; |
308 | } |
309 | |
310 | case Tag::name: |
311 | { |
312 | const Sfnt::FontNames * pName |
313 | = reinterpret_cast<const Sfnt::FontNames *>(pTable); |
314 | if (lTableSize < sizeof(Sfnt::FontNames)) |
315 | return false; |
316 | return be::swap(pName->format) == 0; |
317 | } |
318 | |
319 | case Tag::glyf: |
320 | { |
321 | return (lTableSize >= sizeof(Sfnt::Glyph)); |
322 | } |
323 | |
324 | default: |
325 | break; |
326 | } |
327 | |
328 | return true; |
329 | } |
330 | |
331 | /*---------------------------------------------------------------------------------------------- |
332 | Return the number of glyphs in the font. Should never be less than zero. |
333 | |
334 | Note: this method is not currently used by the Graphite engine. |
335 | ----------------------------------------------------------------------------------------------*/ |
336 | size_t GlyphCount(const void * pMaxp) |
337 | { |
338 | const Sfnt::MaximumProfile * pTable = |
339 | reinterpret_cast<const Sfnt::MaximumProfile *>(pMaxp); |
340 | return be::swap(pTable->num_glyphs); |
341 | } |
342 | |
343 | #ifdef ALL_TTFUTILS |
344 | /*---------------------------------------------------------------------------------------------- |
345 | Return the maximum number of components for any composite glyph in the font. |
346 | |
347 | Note: this method is not currently used by the Graphite engine. |
348 | ----------------------------------------------------------------------------------------------*/ |
349 | size_t MaxCompositeComponentCount(const void * pMaxp) |
350 | { |
351 | const Sfnt::MaximumProfile * pTable = |
352 | reinterpret_cast<const Sfnt::MaximumProfile *>(pMaxp); |
353 | return be::swap(pTable->max_component_elements); |
354 | } |
355 | |
356 | /*---------------------------------------------------------------------------------------------- |
357 | Composite glyphs can be composed of glyphs that are themselves composites. |
358 | This method returns the maximum number of levels like this for any glyph in the font. |
359 | A non-composite glyph has a level of 1. |
360 | |
361 | Note: this method is not currently used by the Graphite engine. |
362 | ----------------------------------------------------------------------------------------------*/ |
363 | size_t MaxCompositeLevelCount(const void * pMaxp) |
364 | { |
365 | const Sfnt::MaximumProfile * pTable = |
366 | reinterpret_cast<const Sfnt::MaximumProfile *>(pMaxp); |
367 | return be::swap(pTable->max_component_depth); |
368 | } |
369 | |
370 | /*---------------------------------------------------------------------------------------------- |
371 | Return the number of glyphs in the font according to a differt source. |
372 | Should never be less than zero. Return -1 on failure. |
373 | |
374 | Note: this method is not currently used by the Graphite engine. |
375 | ----------------------------------------------------------------------------------------------*/ |
376 | size_t LocaGlyphCount(size_t lLocaSize, const void * pHead) //throw(std::domain_error) |
377 | { |
378 | |
379 | const Sfnt::FontHeader * pTable |
380 | = reinterpret_cast<const Sfnt::FontHeader *>(pHead); |
381 | |
382 | if (be::swap(pTable->index_to_loc_format) |
383 | == Sfnt::FontHeader::ShortIndexLocFormat) |
384 | // loca entries are two bytes and have been divided by two |
385 | return (lLocaSize >> 1) - 1; |
386 | |
387 | if (be::swap(pTable->index_to_loc_format) |
388 | == Sfnt::FontHeader::LongIndexLocFormat) |
389 | // loca entries are four bytes |
390 | return (lLocaSize >> 2) - 1; |
391 | |
392 | return -1; |
393 | //throw std::domain_error("head table in inconsistent state. The font may be corrupted"); |
394 | } |
395 | #endif |
396 | |
397 | /*---------------------------------------------------------------------------------------------- |
398 | Return the design units the font is designed with |
399 | ----------------------------------------------------------------------------------------------*/ |
400 | int DesignUnits(const void * pHead) |
401 | { |
402 | const Sfnt::FontHeader * pTable = |
403 | reinterpret_cast<const Sfnt::FontHeader *>(pHead); |
404 | |
405 | return be::swap(pTable->units_per_em); |
406 | } |
407 | |
408 | #ifdef ALL_TTFUTILS |
409 | /*---------------------------------------------------------------------------------------------- |
410 | Return the checksum from the head table, which serves as a unique identifer for the font. |
411 | ----------------------------------------------------------------------------------------------*/ |
412 | int HeadTableCheckSum(const void * pHead) |
413 | { |
414 | const Sfnt::FontHeader * pTable = |
415 | reinterpret_cast<const Sfnt::FontHeader *>(pHead); |
416 | |
417 | return be::swap(pTable->check_sum_adjustment); |
418 | } |
419 | |
420 | /*---------------------------------------------------------------------------------------------- |
421 | Return the create time from the head table. This consists of a 64-bit integer, which |
422 | we return here as two 32-bit integers. |
423 | |
424 | Note: this method is not currently used by the Graphite engine. |
425 | ----------------------------------------------------------------------------------------------*/ |
426 | void HeadTableCreateTime(const void * pHead, |
427 | unsigned int * pnDateBC, unsigned int * pnDateAD) |
428 | { |
429 | const Sfnt::FontHeader * pTable = |
430 | reinterpret_cast<const Sfnt::FontHeader *>(pHead); |
431 | |
432 | *pnDateBC = be::swap(pTable->created[0]); |
433 | *pnDateAD = be::swap(pTable->created[1]); |
434 | } |
435 | |
436 | /*---------------------------------------------------------------------------------------------- |
437 | Return the modify time from the head table.This consists of a 64-bit integer, which |
438 | we return here as two 32-bit integers. |
439 | |
440 | Note: this method is not currently used by the Graphite engine. |
441 | ----------------------------------------------------------------------------------------------*/ |
442 | void HeadTableModifyTime(const void * pHead, |
443 | unsigned int * pnDateBC, unsigned int *pnDateAD) |
444 | { |
445 | const Sfnt::FontHeader * pTable = |
446 | reinterpret_cast<const Sfnt::FontHeader *>(pHead); |
447 | ; |
448 | *pnDateBC = be::swap(pTable->modified[0]); |
449 | *pnDateAD = be::swap(pTable->modified[1]); |
450 | } |
451 | |
452 | /*---------------------------------------------------------------------------------------------- |
453 | Return true if the font is italic. |
454 | ----------------------------------------------------------------------------------------------*/ |
455 | bool IsItalic(const void * pHead) |
456 | { |
457 | const Sfnt::FontHeader * pTable = |
458 | reinterpret_cast<const Sfnt::FontHeader *>(pHead); |
459 | |
460 | return ((be::swap(pTable->mac_style) & 0x00000002) != 0); |
461 | } |
462 | |
463 | /*---------------------------------------------------------------------------------------------- |
464 | Return the ascent for the font |
465 | ----------------------------------------------------------------------------------------------*/ |
466 | int FontAscent(const void * pOs2) |
467 | { |
468 | const Sfnt::Compatibility * pTable = reinterpret_cast<const Sfnt::Compatibility *>(pOs2); |
469 | |
470 | return be::swap(pTable->win_ascent); |
471 | } |
472 | |
473 | /*---------------------------------------------------------------------------------------------- |
474 | Return the descent for the font |
475 | ----------------------------------------------------------------------------------------------*/ |
476 | int FontDescent(const void * pOs2) |
477 | { |
478 | const Sfnt::Compatibility * pTable = reinterpret_cast<const Sfnt::Compatibility *>(pOs2); |
479 | |
480 | return be::swap(pTable->win_descent); |
481 | } |
482 | |
483 | /*---------------------------------------------------------------------------------------------- |
484 | Get the bold and italic style bits. |
485 | Return true if successful. false otherwise. |
486 | In addition to checking the OS/2 table, one could also check |
487 | the head table's macStyle field (overridden by the OS/2 table on Win) |
488 | the sub-family name in the name table (though this can contain oblique, dark, etc too) |
489 | ----------------------------------------------------------------------------------------------*/ |
490 | bool FontOs2Style(const void *pOs2, bool & fBold, bool & fItalic) |
491 | { |
492 | const Sfnt::Compatibility * pTable = reinterpret_cast<const Sfnt::Compatibility *>(pOs2); |
493 | |
494 | fBold = (be::swap(pTable->fs_selection) & Sfnt::Compatibility::Bold) != 0; |
495 | fItalic = (be::swap(pTable->fs_selection) & Sfnt::Compatibility::Italic) != 0; |
496 | |
497 | return true; |
498 | } |
499 | #endif |
500 | |
501 | /*---------------------------------------------------------------------------------------------- |
502 | Method for searching name table. |
503 | ----------------------------------------------------------------------------------------------*/ |
504 | bool GetNameInfo(const void * pName, int nPlatformId, int nEncodingId, |
505 | int nLangId, int nNameId, size_t & lOffset, size_t & lSize) |
506 | { |
507 | lOffset = 0; |
508 | lSize = 0; |
509 | |
510 | const Sfnt::FontNames * pTable = reinterpret_cast<const Sfnt::FontNames *>(pName); |
511 | uint16 cRecord = be::swap(pTable->count); |
512 | uint16 nRecordOffset = be::swap(pTable->string_offset); |
513 | const Sfnt::NameRecord * pRecord = reinterpret_cast<const Sfnt::NameRecord *>(pTable + 1); |
514 | |
515 | for (int i = 0; i < cRecord; ++i) |
516 | { |
517 | if (be::swap(pRecord->platform_id) == nPlatformId && |
518 | be::swap(pRecord->platform_specific_id) == nEncodingId && |
519 | be::swap(pRecord->language_id) == nLangId && |
520 | be::swap(pRecord->name_id) == nNameId) |
521 | { |
522 | lOffset = be::swap(pRecord->offset) + nRecordOffset; |
523 | lSize = be::swap(pRecord->length); |
524 | return true; |
525 | } |
526 | pRecord++; |
527 | } |
528 | |
529 | return false; |
530 | } |
531 | |
532 | #ifdef ALL_TTFUTILS |
533 | /*---------------------------------------------------------------------------------------------- |
534 | Return all the lang-IDs that have data for the given name-IDs. Assume that there is room |
535 | in the return array (langIdList) for 128 items. The purpose of this method is to return |
536 | a list of all possible lang-IDs. |
537 | ----------------------------------------------------------------------------------------------*/ |
538 | int GetLangsForNames(const void * pName, int nPlatformId, int nEncodingId, |
539 | int * nameIdList, int cNameIds, short * langIdList) |
540 | { |
541 | const Sfnt::FontNames * pTable = reinterpret_cast<const Sfnt::FontNames *>(pName); |
542 | int cLangIds = 0; |
543 | uint16 cRecord = be::swap(pTable->count); |
544 | if (cRecord > 127) return cLangIds; |
545 | //uint16 nRecordOffset = swapw(pTable->stringOffset); |
546 | const Sfnt::NameRecord * pRecord = reinterpret_cast<const Sfnt::NameRecord *>(pTable + 1); |
547 | |
548 | for (int i = 0; i < cRecord; ++i) |
549 | { |
550 | if (be::swap(pRecord->platform_id) == nPlatformId && |
551 | be::swap(pRecord->platform_specific_id) == nEncodingId) |
552 | { |
553 | bool fNameFound = false; |
554 | int nLangId = be::swap(pRecord->language_id); |
555 | int nNameId = be::swap(pRecord->name_id); |
556 | for (int j = 0; j < cNameIds; j++) |
557 | { |
558 | if (nNameId == nameIdList[j]) |
559 | { |
560 | fNameFound = true; |
561 | break; |
562 | } |
563 | } |
564 | if (fNameFound) |
565 | { |
566 | // Add it if it's not there. |
567 | int ilang; |
568 | for (ilang = 0; ilang < cLangIds; ilang++) |
569 | if (langIdList[ilang] == nLangId) |
570 | break; |
571 | if (ilang >= cLangIds) |
572 | { |
573 | langIdList[cLangIds] = short(nLangId); |
574 | cLangIds++; |
575 | } |
576 | if (cLangIds == 128) |
577 | return cLangIds; |
578 | } |
579 | } |
580 | pRecord++; |
581 | } |
582 | |
583 | return cLangIds; |
584 | } |
585 | |
586 | /*---------------------------------------------------------------------------------------------- |
587 | Get the offset and size of the font family name in English for the MS Platform with Unicode |
588 | writing system. The offset is within the pName data. The string is double byte with MSB |
589 | first. |
590 | ----------------------------------------------------------------------------------------------*/ |
591 | bool Get31EngFamilyInfo(const void * pName, size_t & lOffset, size_t & lSize) |
592 | { |
593 | return GetNameInfo(pName, Sfnt::NameRecord::Microsoft, 1, 1033, |
594 | Sfnt::NameRecord::Family, lOffset, lSize); |
595 | } |
596 | |
597 | /*---------------------------------------------------------------------------------------------- |
598 | Get the offset and size of the full font name in English for the MS Platform with Unicode |
599 | writing system. The offset is within the pName data. The string is double byte with MSB |
600 | first. |
601 | |
602 | Note: this method is not currently used by the Graphite engine. |
603 | ----------------------------------------------------------------------------------------------*/ |
604 | bool Get31EngFullFontInfo(const void * pName, size_t & lOffset, size_t & lSize) |
605 | { |
606 | return GetNameInfo(pName, Sfnt::NameRecord::Microsoft, 1, 1033, |
607 | Sfnt::NameRecord::Fullname, lOffset, lSize); |
608 | } |
609 | |
610 | /*---------------------------------------------------------------------------------------------- |
611 | Get the offset and size of the font family name in English for the MS Platform with Symbol |
612 | writing system. The offset is within the pName data. The string is double byte with MSB |
613 | first. |
614 | ----------------------------------------------------------------------------------------------*/ |
615 | bool Get30EngFamilyInfo(const void * pName, size_t & lOffset, size_t & lSize) |
616 | { |
617 | return GetNameInfo(pName, Sfnt::NameRecord::Microsoft, 0, 1033, |
618 | Sfnt::NameRecord::Family, lOffset, lSize); |
619 | } |
620 | |
621 | /*---------------------------------------------------------------------------------------------- |
622 | Get the offset and size of the full font name in English for the MS Platform with Symbol |
623 | writing system. The offset is within the pName data. The string is double byte with MSB |
624 | first. |
625 | |
626 | Note: this method is not currently used by the Graphite engine. |
627 | ----------------------------------------------------------------------------------------------*/ |
628 | bool Get30EngFullFontInfo(const void * pName, size_t & lOffset, size_t & lSize) |
629 | { |
630 | return GetNameInfo(pName, Sfnt::NameRecord::Microsoft, 0, 1033, |
631 | Sfnt::NameRecord::Fullname, lOffset, lSize); |
632 | } |
633 | |
634 | /*---------------------------------------------------------------------------------------------- |
635 | Return the Glyph ID for a given Postscript name. This method finds the first glyph which |
636 | matches the requested Postscript name. Ideally every glyph should have a unique Postscript |
637 | name (except for special names such as .notdef), but this is not always true. |
638 | On failure return value less than zero. |
639 | -1 - table search failed |
640 | -2 - format 3 table (no Postscript glyph info) |
641 | -3 - other failures |
642 | |
643 | Note: this method is not currently used by the Graphite engine. |
644 | ----------------------------------------------------------------------------------------------*/ |
645 | int PostLookup(const void * pPost, size_t lPostSize, const void * pMaxp, |
646 | const char * pPostName) |
647 | { |
648 | using namespace Sfnt; |
649 | |
650 | const Sfnt::PostScriptGlyphName * pTable |
651 | = reinterpret_cast<const Sfnt::PostScriptGlyphName *>(pPost); |
652 | fixed format = be::swap(pTable->format); |
653 | |
654 | if (format == PostScriptGlyphName::Format3) |
655 | { // format 3 - no Postscript glyph info in font |
656 | return -2; |
657 | } |
658 | |
659 | // search for given Postscript name among the standard names |
660 | int iPostName = -1; // index in standard names |
661 | for (int i = 0; i < kcPostNames; i++) |
662 | { |
663 | if (!strcmp(pPostName, rgPostName[i])) |
664 | { |
665 | iPostName = i; |
666 | break; |
667 | } |
668 | } |
669 | |
670 | if (format == PostScriptGlyphName::Format1) |
671 | { // format 1 - use standard Postscript names |
672 | return iPostName; |
673 | } |
674 | |
675 | if (format == PostScriptGlyphName::Format25) |
676 | { |
677 | if (iPostName == -1) |
678 | return -1; |
679 | |
680 | const PostScriptGlyphName25 * pTable25 |
681 | = static_cast<const PostScriptGlyphName25 *>(pTable); |
682 | int cnGlyphs = GlyphCount(pMaxp); |
683 | for (gid16 nGlyphId = 0; nGlyphId < cnGlyphs && nGlyphId < kcPostNames; |
684 | nGlyphId++) |
685 | { // glyph_name_index25 contains bytes so no byte swapping needed |
686 | // search for first glyph id that uses the standard name |
687 | if (nGlyphId + pTable25->offset[nGlyphId] == iPostName) |
688 | return nGlyphId; |
689 | } |
690 | } |
691 | |
692 | if (format == PostScriptGlyphName::Format2) |
693 | { // format 2 |
694 | const PostScriptGlyphName2 * pTable2 |
695 | = static_cast<const PostScriptGlyphName2 *>(pTable); |
696 | |
697 | int cnGlyphs = be::swap(pTable2->number_of_glyphs); |
698 | |
699 | if (iPostName != -1) |
700 | { // did match a standard name, look for first glyph id mapped to that name |
701 | for (gid16 nGlyphId = 0; nGlyphId < cnGlyphs; nGlyphId++) |
702 | { |
703 | if (be::swap(pTable2->glyph_name_index[nGlyphId]) == iPostName) |
704 | return nGlyphId; |
705 | } |
706 | } |
707 | |
708 | { // did not match a standard name, search font specific names |
709 | size_t nStrSizeGoal = strlen(pPostName); |
710 | const char * pFirstGlyphName = reinterpret_cast<const char *>( |
711 | &pTable2->glyph_name_index[0] + cnGlyphs); |
712 | const char * pGlyphName = pFirstGlyphName; |
713 | int iInNames = 0; // index in font specific names |
714 | bool fFound = false; |
715 | const char * const endOfTable |
716 | = reinterpret_cast<const char *>(pTable2) + lPostSize; |
717 | while (pGlyphName < endOfTable && !fFound) |
718 | { // search Pascal strings for first matching name |
719 | size_t nStringSize = size_t(*pGlyphName); |
720 | if (nStrSizeGoal != nStringSize || |
721 | strncmp(pGlyphName + 1, pPostName, nStringSize)) |
722 | { // did not match |
723 | ++iInNames; |
724 | pGlyphName += nStringSize + 1; |
725 | } |
726 | else |
727 | { // did match |
728 | fFound = true; |
729 | } |
730 | } |
731 | if (!fFound) |
732 | return -1; // no font specific name matches request |
733 | |
734 | iInNames += kcPostNames; |
735 | for (gid16 nGlyphId = 0; nGlyphId < cnGlyphs; nGlyphId++) |
736 | { // search for first glyph id that maps to the found string index |
737 | if (be::swap(pTable2->glyph_name_index[nGlyphId]) == iInNames) |
738 | return nGlyphId; |
739 | } |
740 | return -1; // no glyph mapped to this index (very strange) |
741 | } |
742 | } |
743 | |
744 | return -3; |
745 | } |
746 | |
747 | /*---------------------------------------------------------------------------------------------- |
748 | Convert a Unicode character string from big endian (MSB first, Motorola) format to little |
749 | endian (LSB first, Intel) format. |
750 | nSize is the number of Unicode characters in the string. It should not include any |
751 | terminating null. If nSize is 0, it is assumed the string is null terminated. nSize |
752 | defaults to 0. |
753 | Return true if successful, false otherwise. |
754 | ----------------------------------------------------------------------------------------------*/ |
755 | void SwapWString(void * pWStr, size_t nSize /* = 0 */) //throw (std::invalid_argument) |
756 | { |
757 | if (pWStr == 0) |
758 | { |
759 | // throw std::invalid_argument("null pointer given"); |
760 | return; |
761 | } |
762 | |
763 | uint16 * pStr = reinterpret_cast<uint16 *>(pWStr); |
764 | uint16 * const pStrEnd = pStr + (nSize == 0 ? wcslen((const wchar_t*)pStr) : nSize); |
765 | |
766 | for (; pStr != pStrEnd; ++pStr) |
767 | *pStr = be::swap(*pStr); |
768 | // std::transform(pStr, pStrEnd, pStr, read<uint16>); |
769 | |
770 | // for (int i = 0; i < nSize; i++) |
771 | // { // swap the wide characters in the string |
772 | // pStr[i] = utf16(be::swap(uint16(pStr[i]))); |
773 | // } |
774 | } |
775 | #endif |
776 | |
777 | /*---------------------------------------------------------------------------------------------- |
778 | Get the left-side bearing and and advance width based on the given tables and Glyph ID |
779 | Return true if successful, false otherwise. On false, one or both value could be INT_MIN |
780 | ----------------------------------------------------------------------------------------------*/ |
781 | bool HorMetrics(gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize, const void * pHhea, |
782 | int & nLsb, unsigned int & nAdvWid) |
783 | { |
784 | const Sfnt::HorizontalMetric * phmtx = |
785 | reinterpret_cast<const Sfnt::HorizontalMetric *>(pHmtx); |
786 | |
787 | const Sfnt::HorizontalHeader * phhea = |
788 | reinterpret_cast<const Sfnt::HorizontalHeader *>(pHhea); |
789 | |
790 | size_t cLongHorMetrics = be::swap(phhea->num_long_hor_metrics); |
791 | if (nGlyphId < cLongHorMetrics) |
792 | { // glyph id is acceptable |
793 | if ((nGlyphId + 1) * sizeof(Sfnt::HorizontalMetric) > lHmtxSize) return false; |
794 | nAdvWid = be::swap(phmtx[nGlyphId].advance_width); |
795 | nLsb = be::swap(phmtx[nGlyphId].left_side_bearing); |
796 | } |
797 | else |
798 | { |
799 | // guard against bad glyph id |
800 | size_t lLsbOffset = sizeof(Sfnt::HorizontalMetric) * cLongHorMetrics + |
801 | sizeof(int16) * (nGlyphId - cLongHorMetrics); // offset in bytes |
802 | // We test like this as LsbOffset is an offset not a length. |
803 | if (lLsbOffset >= lHmtxSize - sizeof(int16) || cLongHorMetrics == 0) |
804 | { |
805 | nLsb = 0; |
806 | return false; |
807 | } |
808 | nAdvWid = be::swap(phmtx[cLongHorMetrics - 1].advance_width); |
809 | nLsb = be::peek<int16>(reinterpret_cast<const byte *>(phmtx) + lLsbOffset); |
810 | } |
811 | |
812 | return true; |
813 | } |
814 | |
815 | /*---------------------------------------------------------------------------------------------- |
816 | Return a pointer to the requested cmap subtable. By default find the Microsoft Unicode |
817 | subtable. Pass nEncoding as -1 to find first table that matches only nPlatformId. |
818 | Return NULL if the subtable cannot be found. |
819 | ----------------------------------------------------------------------------------------------*/ |
820 | const void * FindCmapSubtable(const void * pCmap, int nPlatformId, /* =3 */ int nEncodingId, /* = 1 */ size_t length) |
821 | { |
822 | const Sfnt::CharacterCodeMap * pTable = reinterpret_cast<const Sfnt::CharacterCodeMap *>(pCmap); |
823 | uint16 csuPlatforms = be::swap(pTable->num_subtables); |
824 | if (length && (sizeof(Sfnt::CharacterCodeMap) + 8 * (csuPlatforms - 1) > length)) |
825 | return NULL; |
826 | for (int i = 0; i < csuPlatforms; i++) |
827 | { |
828 | if (be::swap(pTable->encoding[i].platform_id) == nPlatformId && |
829 | (nEncodingId == -1 || be::swap(pTable->encoding[i].platform_specific_id) == nEncodingId)) |
830 | { |
831 | uint32 offset = be::swap(pTable->encoding[i].offset); |
832 | const uint8 * pRtn = reinterpret_cast<const uint8 *>(pCmap) + offset; |
833 | if (length) |
834 | { |
835 | if (offset > length - 2) return NULL; |
836 | uint16 format = be::read<uint16>(pRtn); |
837 | if (format == 4) |
838 | { |
839 | if (offset > length - 4) return NULL; |
840 | uint16 subTableLength = be::peek<uint16>(pRtn); |
841 | if (i + 1 == csuPlatforms) |
842 | { |
843 | if (subTableLength > length - offset) |
844 | return NULL; |
845 | } |
846 | else if (subTableLength > be::swap(pTable->encoding[i+1].offset)) |
847 | return NULL; |
848 | } |
849 | if (format == 12) |
850 | { |
851 | if (offset > length - 6) return NULL; |
852 | uint32 subTableLength = be::peek<uint32>(pRtn); |
853 | if (i + 1 == csuPlatforms) |
854 | { |
855 | if (subTableLength > length - offset) |
856 | return NULL; |
857 | } |
858 | else if (subTableLength > be::swap(pTable->encoding[i+1].offset)) |
859 | return NULL; |
860 | } |
861 | } |
862 | return reinterpret_cast<const uint8 *>(pCmap) + offset; |
863 | } |
864 | } |
865 | |
866 | return 0; |
867 | } |
868 | |
869 | /*---------------------------------------------------------------------------------------------- |
870 | Check the Microsoft Unicode subtable for expected values |
871 | ----------------------------------------------------------------------------------------------*/ |
872 | bool CheckCmapSubtable4(const void * pCmapSubtable4, const void * pCmapEnd /*, unsigned int maxgid*/) |
873 | { |
874 | size_t table_len = (const byte *)pCmapEnd - (const byte *)pCmapSubtable4; |
875 | if (!pCmapSubtable4) return false; |
876 | const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable4); |
877 | // Bob H say some freeware TT fonts have version 1 (eg, CALIGULA.TTF) |
878 | // so don't check subtable version. 21 Mar 2002 spec changes version to language. |
879 | if (table_len < sizeof(*pTable) || be::swap(pTable->format) != 4) return false; |
880 | const Sfnt::CmapSubTableFormat4 * pTable4 = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmapSubtable4); |
881 | if (table_len < sizeof(*pTable4)) |
882 | return false; |
883 | uint16 length = be::swap(pTable4->length); |
884 | if (length > table_len) |
885 | return false; |
886 | if (length < sizeof(Sfnt::CmapSubTableFormat4)) |
887 | return false; |
888 | uint16 nRanges = be::swap(pTable4->seg_count_x2) >> 1; |
889 | if (!nRanges || length < sizeof(Sfnt::CmapSubTableFormat4) + 4 * nRanges * sizeof(uint16)) |
890 | return false; |
891 | // check last range is properly terminated |
892 | uint16 chEnd = be::peek<uint16>(pTable4->end_code + nRanges - 1); |
893 | if (chEnd != 0xFFFF) |
894 | return false; |
895 | #if 0 |
896 | int lastend = -1; |
897 | for (int i = 0; i < nRanges; ++i) |
898 | { |
899 | uint16 end = be::peek<uint16>(pTable4->end_code + i); |
900 | uint16 start = be::peek<uint16>(pTable4->end_code + nRanges + 1 + i); |
901 | int16 delta = be::peek<int16>(pTable4->end_code + 2*nRanges + 1 + i); |
902 | uint16 offset = be::peek<uint16>(pTable4->end_code + 3*nRanges + 1 + i); |
903 | if (lastend >= end || lastend >= start) |
904 | return false; |
905 | if (offset) |
906 | { |
907 | const uint16 *gstart = pTable4->end_code + 3*nRanges + 1 + i + (offset >> 1); |
908 | const uint16 *gend = gstart + end - start; |
909 | if ((char *)gend >= (char *)pCmapSubtable4 + length) |
910 | return false; |
911 | while (gstart <= gend) |
912 | { |
913 | uint16 g = be::peek<uint16>(gstart++); |
914 | if (g && ((g + delta) & 0xFFFF) > maxgid) |
915 | return false; |
916 | } |
917 | } |
918 | else if (((delta + end) & 0xFFFF) > maxgid) |
919 | return false; |
920 | lastend = end; |
921 | } |
922 | #endif |
923 | return true; |
924 | } |
925 | |
926 | /*---------------------------------------------------------------------------------------------- |
927 | Return the Glyph ID for the given Unicode ID in the Microsoft Unicode subtable. |
928 | (Actually this code only depends on subtable being format 4.) |
929 | Return 0 if the Unicode ID is not in the subtable. |
930 | ----------------------------------------------------------------------------------------------*/ |
931 | gid16 CmapSubtable4Lookup(const void * pCmapSubtabel4, unsigned int nUnicodeId, int rangeKey) |
932 | { |
933 | const Sfnt::CmapSubTableFormat4 * pTable = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmapSubtabel4); |
934 | |
935 | uint16 nSeg = be::swap(pTable->seg_count_x2) >> 1; |
936 | |
937 | uint16 n; |
938 | const uint16 * pLeft, * pMid; |
939 | uint16 cMid, chStart, chEnd; |
940 | |
941 | if (rangeKey) |
942 | { |
943 | pMid = &(pTable->end_code[rangeKey]); |
944 | chEnd = be::peek<uint16>(pMid); |
945 | } |
946 | else |
947 | { |
948 | // Binary search of the endCode[] array |
949 | pLeft = &(pTable->end_code[0]); |
950 | n = nSeg; |
951 | while (n > 0) |
952 | { |
953 | cMid = n >> 1; // Pick an element in the middle |
954 | pMid = pLeft + cMid; |
955 | chEnd = be::peek<uint16>(pMid); |
956 | if (nUnicodeId <= chEnd) |
957 | { |
958 | if (cMid == 0 || nUnicodeId > be::peek<uint16>(pMid -1)) |
959 | break; // Must be this seg or none! |
960 | n = cMid; // Continue on left side, omitting mid point |
961 | } |
962 | else |
963 | { |
964 | pLeft = pMid + 1; // Continue on right side, omitting mid point |
965 | n -= (cMid + 1); |
966 | } |
967 | } |
968 | |
969 | if (!n) |
970 | return 0; |
971 | } |
972 | |
973 | // Ok, we're down to one segment and pMid points to the endCode element |
974 | // Either this is it or none is. |
975 | |
976 | chStart = be::peek<uint16>(pMid += nSeg + 1); |
977 | if (chEnd >= nUnicodeId && nUnicodeId >= chStart) |
978 | { |
979 | // Found correct segment. Find Glyph Id |
980 | int16 idDelta = be::peek<uint16>(pMid += nSeg); |
981 | uint16 idRangeOffset = be::peek<uint16>(pMid += nSeg); |
982 | |
983 | if (idRangeOffset == 0) |
984 | return (uint16)(idDelta + nUnicodeId); // must use modulus 2^16 |
985 | |
986 | // Look up value in glyphIdArray |
987 | const ptrdiff_t offset = (nUnicodeId - chStart) + (idRangeOffset >> 1) + |
988 | (pMid - reinterpret_cast<const uint16 *>(pTable)); |
989 | if (offset * 2 + 1 >= be::swap<uint16>(pTable->length)) |
990 | return 0; |
991 | gid16 nGlyphId = be::peek<uint16>(reinterpret_cast<const uint16 *>(pTable)+offset); |
992 | // If this value is 0, return 0. Else add the idDelta |
993 | return nGlyphId ? nGlyphId + idDelta : 0; |
994 | } |
995 | |
996 | return 0; |
997 | } |
998 | |
999 | /*---------------------------------------------------------------------------------------------- |
1000 | Return the next Unicode value in the cmap. Pass 0 to obtain the first item. |
1001 | Returns 0xFFFF as the last item. |
1002 | pRangeKey is an optional key that is used to optimize the search; its value is the range |
1003 | in which the character is found. |
1004 | ----------------------------------------------------------------------------------------------*/ |
1005 | unsigned int CmapSubtable4NextCodepoint(const void *pCmap31, unsigned int nUnicodeId, int * pRangeKey) |
1006 | { |
1007 | const Sfnt::CmapSubTableFormat4 * pTable = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmap31); |
1008 | |
1009 | uint16 nRange = be::swap(pTable->seg_count_x2) >> 1; |
1010 | |
1011 | uint32 nUnicodePrev = (uint32)nUnicodeId; |
1012 | |
1013 | const uint16 * pStartCode = &(pTable->end_code[0]) |
1014 | + nRange // length of end code array |
1015 | + 1; // reserved word |
1016 | |
1017 | if (nUnicodePrev == 0) |
1018 | { |
1019 | // return the first codepoint. |
1020 | if (pRangeKey) |
1021 | *pRangeKey = 0; |
1022 | return be::peek<uint16>(pStartCode); |
1023 | } |
1024 | else if (nUnicodePrev >= 0xFFFF) |
1025 | { |
1026 | if (pRangeKey) |
1027 | *pRangeKey = nRange - 1; |
1028 | return 0xFFFF; |
1029 | } |
1030 | |
1031 | int iRange = (pRangeKey) ? *pRangeKey : 0; |
1032 | // Just in case we have a bad key: |
1033 | while (iRange > 0 && be::peek<uint16>(pStartCode + iRange) > nUnicodePrev) |
1034 | iRange--; |
1035 | while (iRange < nRange - 1 && be::peek<uint16>(pTable->end_code + iRange) < nUnicodePrev) |
1036 | iRange++; |
1037 | |
1038 | // Now iRange is the range containing nUnicodePrev. |
1039 | unsigned int nStartCode = be::peek<uint16>(pStartCode + iRange); |
1040 | unsigned int nEndCode = be::peek<uint16>(pTable->end_code + iRange); |
1041 | |
1042 | if (nStartCode > nUnicodePrev) |
1043 | // Oops, nUnicodePrev is not in the cmap! Adjust so we get a reasonable |
1044 | // answer this time around. |
1045 | nUnicodePrev = nStartCode - 1; |
1046 | |
1047 | if (nEndCode > nUnicodePrev) |
1048 | { |
1049 | // Next is in the same range; it is the next successive codepoint. |
1050 | if (pRangeKey) |
1051 | *pRangeKey = iRange; |
1052 | return nUnicodePrev + 1; |
1053 | } |
1054 | |
1055 | // Otherwise the next codepoint is the first one in the next range. |
1056 | // There is guaranteed to be a next range because there must be one that |
1057 | // ends with 0xFFFF. |
1058 | if (pRangeKey) |
1059 | *pRangeKey = iRange + 1; |
1060 | return (iRange + 1 >= nRange) ? 0xFFFF : be::peek<uint16>(pStartCode + iRange + 1); |
1061 | } |
1062 | |
1063 | /*---------------------------------------------------------------------------------------------- |
1064 | Check the Microsoft UCS-4 subtable for expected values. |
1065 | ----------------------------------------------------------------------------------------------*/ |
1066 | bool CheckCmapSubtable12(const void *pCmapSubtable12, const void *pCmapEnd /*, unsigned int maxgid*/) |
1067 | { |
1068 | size_t table_len = (const byte *)pCmapEnd - (const byte *)pCmapSubtable12; |
1069 | if (!pCmapSubtable12) return false; |
1070 | const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable12); |
1071 | if (table_len < sizeof(*pTable) || be::swap(pTable->format) != 12) |
1072 | return false; |
1073 | const Sfnt::CmapSubTableFormat12 * pTable12 = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmapSubtable12); |
1074 | if (table_len < sizeof(*pTable12)) |
1075 | return false; |
1076 | uint32 length = be::swap(pTable12->length); |
1077 | if (length > table_len) |
1078 | return false; |
1079 | if (length < sizeof(Sfnt::CmapSubTableFormat12)) |
1080 | return false; |
1081 | uint32 num_groups = be::swap(pTable12->num_groups); |
1082 | if (num_groups > 0x10000000 || length != (sizeof(Sfnt::CmapSubTableFormat12) + (num_groups - 1) * sizeof(uint32) * 3)) |
1083 | return false; |
1084 | #if 0 |
1085 | for (unsigned int i = 0; i < num_groups; ++i) |
1086 | { |
1087 | if (be::swap(pTable12->group[i].end_char_code) - be::swap(pTable12->group[i].start_char_code) + be::swap(pTable12->group[i].start_glyph_id) > maxgid) |
1088 | return false; |
1089 | if (i > 0 && be::swap(pTable12->group[i].start_char_code) <= be::swap(pTable12->group[i-1].end_char_code)) |
1090 | return false; |
1091 | } |
1092 | #endif |
1093 | return true; |
1094 | } |
1095 | |
1096 | /*---------------------------------------------------------------------------------------------- |
1097 | Return the Glyph ID for the given Unicode ID in the Microsoft UCS-4 subtable. |
1098 | (Actually this code only depends on subtable being format 12.) |
1099 | Return 0 if the Unicode ID is not in the subtable. |
1100 | ----------------------------------------------------------------------------------------------*/ |
1101 | gid16 CmapSubtable12Lookup(const void * pCmap310, unsigned int uUnicodeId, int rangeKey) |
1102 | { |
1103 | const Sfnt::CmapSubTableFormat12 * pTable = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmap310); |
1104 | |
1105 | //uint32 uLength = be::swap(pTable->length); //could use to test for premature end of table |
1106 | uint32 ucGroups = be::swap(pTable->num_groups); |
1107 | |
1108 | for (unsigned int i = rangeKey; i < ucGroups; i++) |
1109 | { |
1110 | uint32 uStartCode = be::swap(pTable->group[i].start_char_code); |
1111 | uint32 uEndCode = be::swap(pTable->group[i].end_char_code); |
1112 | if (uUnicodeId >= uStartCode && uUnicodeId <= uEndCode) |
1113 | { |
1114 | uint32 uDiff = uUnicodeId - uStartCode; |
1115 | uint32 uStartGid = be::swap(pTable->group[i].start_glyph_id); |
1116 | return static_cast<gid16>(uStartGid + uDiff); |
1117 | } |
1118 | } |
1119 | |
1120 | return 0; |
1121 | } |
1122 | |
1123 | /*---------------------------------------------------------------------------------------------- |
1124 | Return the next Unicode value in the cmap. Pass 0 to obtain the first item. |
1125 | Returns 0x10FFFF as the last item. |
1126 | pRangeKey is an optional key that is used to optimize the search; its value is the range |
1127 | in which the character is found. |
1128 | ----------------------------------------------------------------------------------------------*/ |
1129 | unsigned int CmapSubtable12NextCodepoint(const void *pCmap310, unsigned int nUnicodeId, int * pRangeKey) |
1130 | { |
1131 | const Sfnt::CmapSubTableFormat12 * pTable = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmap310); |
1132 | |
1133 | int nRange = be::swap(pTable->num_groups); |
1134 | |
1135 | uint32 nUnicodePrev = (uint32)nUnicodeId; |
1136 | |
1137 | if (nUnicodePrev == 0) |
1138 | { |
1139 | // return the first codepoint. |
1140 | if (pRangeKey) |
1141 | *pRangeKey = 0; |
1142 | return be::swap(pTable->group[0].start_char_code); |
1143 | } |
1144 | else if (nUnicodePrev >= 0x10FFFF) |
1145 | { |
1146 | if (pRangeKey) |
1147 | *pRangeKey = nRange; |
1148 | return 0x10FFFF; |
1149 | } |
1150 | |
1151 | int iRange = (pRangeKey) ? *pRangeKey : 0; |
1152 | // Just in case we have a bad key: |
1153 | while (iRange > 0 && be::swap(pTable->group[iRange].start_char_code) > nUnicodePrev) |
1154 | iRange--; |
1155 | while (iRange < nRange - 1 && be::swap(pTable->group[iRange].end_char_code) < nUnicodePrev) |
1156 | iRange++; |
1157 | |
1158 | // Now iRange is the range containing nUnicodePrev. |
1159 | |
1160 | unsigned int nStartCode = be::swap(pTable->group[iRange].start_char_code); |
1161 | unsigned int nEndCode = be::swap(pTable->group[iRange].end_char_code); |
1162 | |
1163 | if (nStartCode > nUnicodePrev) |
1164 | // Oops, nUnicodePrev is not in the cmap! Adjust so we get a reasonable |
1165 | // answer this time around. |
1166 | nUnicodePrev = nStartCode - 1; |
1167 | |
1168 | if (nEndCode > nUnicodePrev) |
1169 | { |
1170 | // Next is in the same range; it is the next successive codepoint. |
1171 | if (pRangeKey) |
1172 | *pRangeKey = iRange; |
1173 | return nUnicodePrev + 1; |
1174 | } |
1175 | |
1176 | // Otherwise the next codepoint is the first one in the next range, or 10FFFF if we're done. |
1177 | if (pRangeKey) |
1178 | *pRangeKey = iRange + 1; |
1179 | return (iRange + 1 >= nRange) ? 0x10FFFF : be::swap(pTable->group[iRange + 1].start_char_code); |
1180 | } |
1181 | |
1182 | /*---------------------------------------------------------------------------------------------- |
1183 | Return the offset stored in the loca table for the given Glyph ID. |
1184 | (This offset is into the glyf table.) |
1185 | Return -1 if the lookup failed. |
1186 | Technically this method should return an unsigned long but it is unlikely the offset will |
1187 | exceed 2^31. |
1188 | ----------------------------------------------------------------------------------------------*/ |
1189 | size_t LocaLookup(gid16 nGlyphId, |
1190 | const void * pLoca, size_t lLocaSize, |
1191 | const void * pHead) // throw (std::out_of_range) |
1192 | { |
1193 | const Sfnt::FontHeader * pTable = reinterpret_cast<const Sfnt::FontHeader *>(pHead); |
1194 | size_t res = -2; |
1195 | |
1196 | // CheckTable verifies the index_to_loc_format is valid |
1197 | if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::ShortIndexLocFormat) |
1198 | { // loca entries are two bytes and have been divided by two |
1199 | if (lLocaSize > 1 && nGlyphId + 1u < lLocaSize >> 1) // allow sentinel value to be accessed |
1200 | { |
1201 | const uint16 * pShortTable = reinterpret_cast<const uint16 *>(pLoca); |
1202 | res = be::peek<uint16>(pShortTable + nGlyphId) << 1; |
1203 | if (res == static_cast<size_t>(be::peek<uint16>(pShortTable + nGlyphId + 1) << 1)) |
1204 | return -1; |
1205 | } |
1206 | } |
1207 | else if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::LongIndexLocFormat) |
1208 | { // loca entries are four bytes |
1209 | if (lLocaSize > 3 && nGlyphId + 1u < lLocaSize >> 2) |
1210 | { |
1211 | const uint32 * pLongTable = reinterpret_cast<const uint32 *>(pLoca); |
1212 | res = be::peek<uint32>(pLongTable + nGlyphId); |
1213 | if (res == static_cast<size_t>(be::peek<uint32>(pLongTable + nGlyphId + 1))) |
1214 | return -1; |
1215 | } |
1216 | } |
1217 | |
1218 | // only get here if glyph id was bad |
1219 | return res; |
1220 | //throw std::out_of_range("glyph id out of range for font"); |
1221 | } |
1222 | |
1223 | /*---------------------------------------------------------------------------------------------- |
1224 | Return a pointer into the glyf table based on the given offset (from LocaLookup). |
1225 | Return NULL on error. |
1226 | ----------------------------------------------------------------------------------------------*/ |
1227 | void * GlyfLookup(const void * pGlyf, size_t nGlyfOffset, size_t nTableLen) |
1228 | { |
1229 | const uint8 * pByte = reinterpret_cast<const uint8 *>(pGlyf); |
1230 | if (OVERFLOW_OFFSET_CHECK(pByte, nGlyfOffset) || nGlyfOffset >= nTableLen - sizeof(Sfnt::Glyph)) |
1231 | return NULL; |
1232 | return const_cast<uint8 *>(pByte + nGlyfOffset); |
1233 | } |
1234 | |
1235 | /*---------------------------------------------------------------------------------------------- |
1236 | Get the bounding box coordinates for a simple glyf entry (non-composite). |
1237 | Return true if successful, false otherwise. |
1238 | ----------------------------------------------------------------------------------------------*/ |
1239 | bool GlyfBox(const void * pSimpleGlyf, int & xMin, int & yMin, |
1240 | int & xMax, int & yMax) |
1241 | { |
1242 | const Sfnt::Glyph * pGlyph = reinterpret_cast<const Sfnt::Glyph *>(pSimpleGlyf); |
1243 | |
1244 | xMin = be::swap(pGlyph->x_min); |
1245 | yMin = be::swap(pGlyph->y_min); |
1246 | xMax = be::swap(pGlyph->x_max); |
1247 | yMax = be::swap(pGlyph->y_max); |
1248 | |
1249 | return true; |
1250 | } |
1251 | |
1252 | #ifdef ALL_TTFUTILS |
1253 | /*---------------------------------------------------------------------------------------------- |
1254 | Return the number of contours for a simple glyf entry (non-composite) |
1255 | Returning -1 means this is a composite glyph |
1256 | ----------------------------------------------------------------------------------------------*/ |
1257 | int GlyfContourCount(const void * pSimpleGlyf) |
1258 | { |
1259 | const Sfnt::Glyph * pGlyph = reinterpret_cast<const Sfnt::Glyph *>(pSimpleGlyf); |
1260 | return be::swap(pGlyph->number_of_contours); // -1 means composite glyph |
1261 | } |
1262 | |
1263 | /*---------------------------------------------------------------------------------------------- |
1264 | Get the point numbers for the end points of the glyph contours for a simple |
1265 | glyf entry (non-composite). |
1266 | cnPointsTotal - count of contours from GlyfContourCount(); (same as number of end points) |
1267 | prgnContourEndPoints - should point to a buffer large enough to hold cnPoints integers |
1268 | cnPoints - count of points placed in above range |
1269 | Return true if successful, false otherwise. |
1270 | False could indicate a multi-level composite glyphs. |
1271 | ----------------------------------------------------------------------------------------------*/ |
1272 | bool GlyfContourEndPoints(const void * pSimpleGlyf, int * prgnContourEndPoint, |
1273 | int cnPointsTotal, int & cnPoints) |
1274 | { |
1275 | const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf); |
1276 | |
1277 | int cContours = be::swap(pGlyph->number_of_contours); |
1278 | if (cContours < 0) |
1279 | return false; // this method isn't supposed handle composite glyphs |
1280 | |
1281 | for (int i = 0; i < cContours && i < cnPointsTotal; i++) |
1282 | { |
1283 | prgnContourEndPoint[i] = be::swap(pGlyph->end_pts_of_contours[i]); |
1284 | } |
1285 | |
1286 | cnPoints = cContours; |
1287 | return true; |
1288 | } |
1289 | |
1290 | /*---------------------------------------------------------------------------------------------- |
1291 | Get the points for a simple glyf entry (non-composite) |
1292 | cnPointsTotal - count of points from largest end point obtained from GlyfContourEndPoints |
1293 | prgnX & prgnY - should point to buffers large enough to hold cnPointsTotal integers |
1294 | The ranges are parallel so that coordinates for point(n) are found at offset n in both |
1295 | ranges. This is raw point data with relative coordinates. |
1296 | prgbFlag - should point to a buffer a large enough to hold cnPointsTotal bytes |
1297 | This range is parallel to the prgnX & prgnY |
1298 | cnPoints - count of points placed in above ranges |
1299 | Return true if successful, false otherwise. |
1300 | False could indicate a composite glyph |
1301 | ----------------------------------------------------------------------------------------------*/ |
1302 | bool GlyfPoints(const void * pSimpleGlyf, int * prgnX, int * prgnY, |
1303 | char * prgbFlag, int cnPointsTotal, int & cnPoints) |
1304 | { |
1305 | using namespace Sfnt; |
1306 | |
1307 | const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf); |
1308 | int cContours = be::swap(pGlyph->number_of_contours); |
1309 | // return false for composite glyph |
1310 | if (cContours <= 0) |
1311 | return false; |
1312 | int cPts = be::swap(pGlyph->end_pts_of_contours[cContours - 1]) + 1; |
1313 | if (cPts > cnPointsTotal) |
1314 | return false; |
1315 | |
1316 | // skip over bounding box data & point to byte count of instructions (hints) |
1317 | const uint8 * pbGlyph = reinterpret_cast<const uint8 *> |
1318 | (&pGlyph->end_pts_of_contours[cContours]); |
1319 | |
1320 | // skip over hints & point to first flag |
1321 | int cbHints = be::swap(*(uint16 *)pbGlyph); |
1322 | pbGlyph += sizeof(uint16); |
1323 | pbGlyph += cbHints; |
1324 | |
1325 | // load flags & point to first x coordinate |
1326 | int iFlag = 0; |
1327 | while (iFlag < cPts) |
1328 | { |
1329 | if (!(*pbGlyph & SimpleGlyph::Repeat)) |
1330 | { // flag isn't repeated |
1331 | prgbFlag[iFlag] = (char)*pbGlyph; |
1332 | pbGlyph++; |
1333 | iFlag++; |
1334 | } |
1335 | else |
1336 | { // flag is repeated; count specified by next byte |
1337 | char chFlag = (char)*pbGlyph; |
1338 | pbGlyph++; |
1339 | int cFlags = (int)*pbGlyph; |
1340 | pbGlyph++; |
1341 | prgbFlag[iFlag] = chFlag; |
1342 | iFlag++; |
1343 | for (int i = 0; i < cFlags; i++) |
1344 | { |
1345 | prgbFlag[iFlag + i] = chFlag; |
1346 | } |
1347 | iFlag += cFlags; |
1348 | } |
1349 | } |
1350 | if (iFlag != cPts) |
1351 | return false; |
1352 | |
1353 | // load x coordinates |
1354 | iFlag = 0; |
1355 | while (iFlag < cPts) |
1356 | { |
1357 | if (prgbFlag[iFlag] & SimpleGlyph::XShort) |
1358 | { |
1359 | prgnX[iFlag] = *pbGlyph; |
1360 | if (!(prgbFlag[iFlag] & SimpleGlyph::XIsPos)) |
1361 | { |
1362 | prgnX[iFlag] = -prgnX[iFlag]; |
1363 | } |
1364 | pbGlyph++; |
1365 | } |
1366 | else |
1367 | { |
1368 | if (prgbFlag[iFlag] & SimpleGlyph::XIsSame) |
1369 | { |
1370 | prgnX[iFlag] = 0; |
1371 | // do NOT increment pbGlyph |
1372 | } |
1373 | else |
1374 | { |
1375 | prgnX[iFlag] = be::swap(*(int16 *)pbGlyph); |
1376 | pbGlyph += sizeof(int16); |
1377 | } |
1378 | } |
1379 | iFlag++; |
1380 | } |
1381 | |
1382 | // load y coordinates |
1383 | iFlag = 0; |
1384 | while (iFlag < cPts) |
1385 | { |
1386 | if (prgbFlag[iFlag] & SimpleGlyph::YShort) |
1387 | { |
1388 | prgnY[iFlag] = *pbGlyph; |
1389 | if (!(prgbFlag[iFlag] & SimpleGlyph::YIsPos)) |
1390 | { |
1391 | prgnY[iFlag] = -prgnY[iFlag]; |
1392 | } |
1393 | pbGlyph++; |
1394 | } |
1395 | else |
1396 | { |
1397 | if (prgbFlag[iFlag] & SimpleGlyph::YIsSame) |
1398 | { |
1399 | prgnY[iFlag] = 0; |
1400 | // do NOT increment pbGlyph |
1401 | } |
1402 | else |
1403 | { |
1404 | prgnY[iFlag] = be::swap(*(int16 *)pbGlyph); |
1405 | pbGlyph += sizeof(int16); |
1406 | } |
1407 | } |
1408 | iFlag++; |
1409 | } |
1410 | |
1411 | cnPoints = cPts; |
1412 | return true; |
1413 | } |
1414 | |
1415 | /*---------------------------------------------------------------------------------------------- |
1416 | Fill prgnCompId with the component Glyph IDs from pSimpleGlyf. |
1417 | Client must allocate space before calling. |
1418 | pSimpleGlyf - assumed to point to a composite glyph |
1419 | cCompIdTotal - the number of elements in prgnCompId |
1420 | cCompId - the total number of Glyph IDs stored in prgnCompId |
1421 | Return true if successful, false otherwise |
1422 | False could indicate a non-composite glyph or the input array was not big enough |
1423 | ----------------------------------------------------------------------------------------------*/ |
1424 | bool GetComponentGlyphIds(const void * pSimpleGlyf, int * prgnCompId, |
1425 | size_t cnCompIdTotal, size_t & cnCompId) |
1426 | { |
1427 | using namespace Sfnt; |
1428 | |
1429 | if (GlyfContourCount(pSimpleGlyf) >= 0) |
1430 | return false; |
1431 | |
1432 | const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf); |
1433 | // for a composite glyph, the special data begins here |
1434 | const uint8 * pbGlyph = reinterpret_cast<const uint8 *>(&pGlyph->end_pts_of_contours[0]); |
1435 | |
1436 | uint16 GlyphFlags; |
1437 | size_t iCurrentComp = 0; |
1438 | do |
1439 | { |
1440 | GlyphFlags = be::swap(*((uint16 *)pbGlyph)); |
1441 | pbGlyph += sizeof(uint16); |
1442 | prgnCompId[iCurrentComp++] = be::swap(*((uint16 *)pbGlyph)); |
1443 | pbGlyph += sizeof(uint16); |
1444 | if (iCurrentComp >= cnCompIdTotal) |
1445 | return false; |
1446 | int nOffset = 0; |
1447 | nOffset += GlyphFlags & CompoundGlyph::Arg1Arg2Words ? 4 : 2; |
1448 | nOffset += GlyphFlags & CompoundGlyph::HaveScale ? 2 : 0; |
1449 | nOffset += GlyphFlags & CompoundGlyph::HaveXAndYScale ? 4 : 0; |
1450 | nOffset += GlyphFlags & CompoundGlyph::HaveTwoByTwo ? 8 : 0; |
1451 | pbGlyph += nOffset; |
1452 | } while (GlyphFlags & CompoundGlyph::MoreComponents); |
1453 | |
1454 | cnCompId = iCurrentComp; |
1455 | |
1456 | return true; |
1457 | } |
1458 | |
1459 | /*---------------------------------------------------------------------------------------------- |
1460 | Return info on how a component glyph is to be placed |
1461 | pSimpleGlyph - assumed to point to a composite glyph |
1462 | nCompId - glyph id for component of interest |
1463 | bOffset - if true, a & b are the x & y offsets for this component |
1464 | if false, b is the point on this component that is attaching to point a on the |
1465 | preceding glyph |
1466 | Return true if successful, false otherwise |
1467 | False could indicate a non-composite glyph or that component wasn't found |
1468 | ----------------------------------------------------------------------------------------------*/ |
1469 | bool GetComponentPlacement(const void * pSimpleGlyf, int nCompId, |
1470 | bool fOffset, int & a, int & b) |
1471 | { |
1472 | using namespace Sfnt; |
1473 | |
1474 | if (GlyfContourCount(pSimpleGlyf) >= 0) |
1475 | return false; |
1476 | |
1477 | const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf); |
1478 | // for a composite glyph, the special data begins here |
1479 | const uint8 * pbGlyph = reinterpret_cast<const uint8 *>(&pGlyph->end_pts_of_contours[0]); |
1480 | |
1481 | uint16 GlyphFlags; |
1482 | do |
1483 | { |
1484 | GlyphFlags = be::swap(*((uint16 *)pbGlyph)); |
1485 | pbGlyph += sizeof(uint16); |
1486 | if (be::swap(*((uint16 *)pbGlyph)) == nCompId) |
1487 | { |
1488 | pbGlyph += sizeof(uint16); // skip over glyph id of component |
1489 | fOffset = (GlyphFlags & CompoundGlyph::ArgsAreXYValues) == CompoundGlyph::ArgsAreXYValues; |
1490 | |
1491 | if (GlyphFlags & CompoundGlyph::Arg1Arg2Words ) |
1492 | { |
1493 | a = be::swap(*(int16 *)pbGlyph); |
1494 | pbGlyph += sizeof(int16); |
1495 | b = be::swap(*(int16 *)pbGlyph); |
1496 | pbGlyph += sizeof(int16); |
1497 | } |
1498 | else |
1499 | { // args are signed bytes |
1500 | a = *pbGlyph++; |
1501 | b = *pbGlyph++; |
1502 | } |
1503 | return true; |
1504 | } |
1505 | pbGlyph += sizeof(uint16); // skip over glyph id of component |
1506 | int nOffset = 0; |
1507 | nOffset += GlyphFlags & CompoundGlyph::Arg1Arg2Words ? 4 : 2; |
1508 | nOffset += GlyphFlags & CompoundGlyph::HaveScale ? 2 : 0; |
1509 | nOffset += GlyphFlags & CompoundGlyph::HaveXAndYScale ? 4 : 0; |
1510 | nOffset += GlyphFlags & CompoundGlyph::HaveTwoByTwo ? 8 : 0; |
1511 | pbGlyph += nOffset; |
1512 | } while (GlyphFlags & CompoundGlyph::MoreComponents); |
1513 | |
1514 | // didn't find requested component |
1515 | fOffset = true; |
1516 | a = 0; |
1517 | b = 0; |
1518 | return false; |
1519 | } |
1520 | |
1521 | /*---------------------------------------------------------------------------------------------- |
1522 | Return info on how a component glyph is to be transformed |
1523 | pSimpleGlyph - assumed to point to a composite glyph |
1524 | nCompId - glyph id for component of interest |
1525 | flt11, flt11, flt11, flt11 - a 2x2 matrix giving the transform |
1526 | bTransOffset - whether to transform the offset from above method |
1527 | The spec is unclear about the meaning of this flag |
1528 | Currently - initialize to true for MS rasterizer and false for Mac rasterizer, then |
1529 | on return it will indicate whether transform should apply to offset (MSDN CD 10/99) |
1530 | Return true if successful, false otherwise |
1531 | False could indicate a non-composite glyph or that component wasn't found |
1532 | ----------------------------------------------------------------------------------------------*/ |
1533 | bool GetComponentTransform(const void * pSimpleGlyf, int nCompId, |
1534 | float & flt11, float & flt12, float & flt21, float & flt22, |
1535 | bool & fTransOffset) |
1536 | { |
1537 | using namespace Sfnt; |
1538 | |
1539 | if (GlyfContourCount(pSimpleGlyf) >= 0) |
1540 | return false; |
1541 | |
1542 | const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf); |
1543 | // for a composite glyph, the special data begins here |
1544 | const uint8 * pbGlyph = reinterpret_cast<const uint8 *>(&pGlyph->end_pts_of_contours[0]); |
1545 | |
1546 | uint16 GlyphFlags; |
1547 | do |
1548 | { |
1549 | GlyphFlags = be::swap(*((uint16 *)pbGlyph)); |
1550 | pbGlyph += sizeof(uint16); |
1551 | if (be::swap(*((uint16 *)pbGlyph)) == nCompId) |
1552 | { |
1553 | pbGlyph += sizeof(uint16); // skip over glyph id of component |
1554 | pbGlyph += GlyphFlags & CompoundGlyph::Arg1Arg2Words ? 4 : 2; // skip over placement data |
1555 | |
1556 | if (fTransOffset) // MS rasterizer |
1557 | fTransOffset = !(GlyphFlags & CompoundGlyph::UnscaledOffset); |
1558 | else // Apple rasterizer |
1559 | fTransOffset = (GlyphFlags & CompoundGlyph::ScaledOffset) != 0; |
1560 | |
1561 | if (GlyphFlags & CompoundGlyph::HaveScale) |
1562 | { |
1563 | flt11 = fixed_to_float<14>(be::swap(*(uint16 *)pbGlyph)); |
1564 | pbGlyph += sizeof(uint16); |
1565 | flt12 = 0; |
1566 | flt21 = 0; |
1567 | flt22 = flt11; |
1568 | } |
1569 | else if (GlyphFlags & CompoundGlyph::HaveXAndYScale) |
1570 | { |
1571 | flt11 = fixed_to_float<14>(be::swap(*(uint16 *)pbGlyph)); |
1572 | pbGlyph += sizeof(uint16); |
1573 | flt12 = 0; |
1574 | flt21 = 0; |
1575 | flt22 = fixed_to_float<14>(be::swap(*(uint16 *)pbGlyph)); |
1576 | pbGlyph += sizeof(uint16); |
1577 | } |
1578 | else if (GlyphFlags & CompoundGlyph::HaveTwoByTwo) |
1579 | { |
1580 | flt11 = fixed_to_float<14>(be::swap(*(uint16 *)pbGlyph)); |
1581 | pbGlyph += sizeof(uint16); |
1582 | flt12 = fixed_to_float<14>(be::swap(*(uint16 *)pbGlyph)); |
1583 | pbGlyph += sizeof(uint16); |
1584 | flt21 = fixed_to_float<14>(be::swap(*(uint16 *)pbGlyph)); |
1585 | pbGlyph += sizeof(uint16); |
1586 | flt22 = fixed_to_float<14>(be::swap(*(uint16 *)pbGlyph)); |
1587 | pbGlyph += sizeof(uint16); |
1588 | } |
1589 | else |
1590 | { // identity transform |
1591 | flt11 = 1.0; |
1592 | flt12 = 0.0; |
1593 | flt21 = 0.0; |
1594 | flt22 = 1.0; |
1595 | } |
1596 | return true; |
1597 | } |
1598 | pbGlyph += sizeof(uint16); // skip over glyph id of component |
1599 | int nOffset = 0; |
1600 | nOffset += GlyphFlags & CompoundGlyph::Arg1Arg2Words ? 4 : 2; |
1601 | nOffset += GlyphFlags & CompoundGlyph::HaveScale ? 2 : 0; |
1602 | nOffset += GlyphFlags & CompoundGlyph::HaveXAndYScale ? 4 : 0; |
1603 | nOffset += GlyphFlags & CompoundGlyph::HaveTwoByTwo ? 8 : 0; |
1604 | pbGlyph += nOffset; |
1605 | } while (GlyphFlags & CompoundGlyph::MoreComponents); |
1606 | |
1607 | // didn't find requested component |
1608 | fTransOffset = false; |
1609 | flt11 = 1; |
1610 | flt12 = 0; |
1611 | flt21 = 0; |
1612 | flt22 = 1; |
1613 | return false; |
1614 | } |
1615 | #endif |
1616 | |
1617 | /*---------------------------------------------------------------------------------------------- |
1618 | Return a pointer into the glyf table based on the given tables and Glyph ID |
1619 | Since this method doesn't check for spaces, it is good to call IsSpace before using it. |
1620 | Return NULL on error. |
1621 | ----------------------------------------------------------------------------------------------*/ |
1622 | void * GlyfLookup(gid16 nGlyphId, const void * pGlyf, const void * pLoca, |
1623 | size_t lGlyfSize, size_t lLocaSize, const void * pHead) |
1624 | { |
1625 | // test for valid glyph id |
1626 | // CheckTable verifies the index_to_loc_format is valid |
1627 | |
1628 | const Sfnt::FontHeader * pTable |
1629 | = reinterpret_cast<const Sfnt::FontHeader *>(pHead); |
1630 | |
1631 | if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::ShortIndexLocFormat) |
1632 | { // loca entries are two bytes (and have been divided by two) |
1633 | if (nGlyphId >= (lLocaSize >> 1) - 1) // don't allow nGlyphId to access sentinel |
1634 | { |
1635 | // throw std::out_of_range("glyph id out of range for font"); |
1636 | return NULL; |
1637 | } |
1638 | } |
1639 | if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::LongIndexLocFormat) |
1640 | { // loca entries are four bytes |
1641 | if (nGlyphId >= (lLocaSize >> 2) - 1) |
1642 | { |
1643 | // throw std::out_of_range("glyph id out of range for font"); |
1644 | return NULL; |
1645 | } |
1646 | } |
1647 | |
1648 | size_t lGlyfOffset = LocaLookup(nGlyphId, pLoca, lLocaSize, pHead); |
1649 | void * pSimpleGlyf = GlyfLookup(pGlyf, lGlyfOffset, lGlyfSize); // invalid loca offset returns null |
1650 | return pSimpleGlyf; |
1651 | } |
1652 | |
1653 | #ifdef ALL_TTFUTILS |
1654 | /*---------------------------------------------------------------------------------------------- |
1655 | Determine if a particular Glyph ID has any data in the glyf table. If it is white space, |
1656 | there will be no glyf data, though there will be metric data in hmtx, etc. |
1657 | ----------------------------------------------------------------------------------------------*/ |
1658 | bool IsSpace(gid16 nGlyphId, const void * pLoca, size_t lLocaSize, const void * pHead) |
1659 | { |
1660 | size_t lGlyfOffset = LocaLookup(nGlyphId, pLoca, lLocaSize, pHead); |
1661 | |
1662 | // the +1 should always work because there is a sentinel value at the end of the loca table |
1663 | size_t lNextGlyfOffset = LocaLookup(nGlyphId + 1, pLoca, lLocaSize, pHead); |
1664 | |
1665 | return (lNextGlyfOffset - lGlyfOffset) == 0; |
1666 | } |
1667 | |
1668 | /*---------------------------------------------------------------------------------------------- |
1669 | Determine if a particular Glyph ID is a multi-level composite. |
1670 | ----------------------------------------------------------------------------------------------*/ |
1671 | bool IsDeepComposite(gid16 nGlyphId, const void * pGlyf, const void * pLoca, |
1672 | size_t lGlyfSize, long lLocaSize, const void * pHead) |
1673 | { |
1674 | if (IsSpace(nGlyphId, pLoca, lLocaSize, pHead)) {return false;} |
1675 | |
1676 | void * pSimpleGlyf = GlyfLookup(nGlyphId, pGlyf, pLoca, lGlyfSize, lLocaSize, pHead); |
1677 | if (pSimpleGlyf == NULL) |
1678 | return false; // no way to really indicate an error occured here |
1679 | |
1680 | if (GlyfContourCount(pSimpleGlyf) >= 0) |
1681 | return false; |
1682 | |
1683 | int rgnCompId[kMaxGlyphComponents]; // assumes only a limited number of glyph components |
1684 | size_t cCompIdTotal = kMaxGlyphComponents; |
1685 | size_t cCompId = 0; |
1686 | |
1687 | if (!GetComponentGlyphIds(pSimpleGlyf, rgnCompId, cCompIdTotal, cCompId)) |
1688 | return false; |
1689 | |
1690 | for (size_t i = 0; i < cCompId; i++) |
1691 | { |
1692 | pSimpleGlyf = GlyfLookup(static_cast<gid16>(rgnCompId[i]), |
1693 | pGlyf, pLoca, lGlyfSize, lLocaSize, pHead); |
1694 | if (pSimpleGlyf == NULL) {return false;} |
1695 | |
1696 | if (GlyfContourCount(pSimpleGlyf) < 0) |
1697 | return true; |
1698 | } |
1699 | |
1700 | return false; |
1701 | } |
1702 | |
1703 | /*---------------------------------------------------------------------------------------------- |
1704 | Get the bounding box coordinates based on the given tables and Glyph ID |
1705 | Handles both simple and composite glyphs. |
1706 | Return true if successful, false otherwise. On false, all point values will be INT_MIN |
1707 | False may indicate a white space glyph |
1708 | ----------------------------------------------------------------------------------------------*/ |
1709 | bool GlyfBox(gid16 nGlyphId, const void * pGlyf, const void * pLoca, |
1710 | size_t lGlyfSize, size_t lLocaSize, const void * pHead, int & xMin, int & yMin, int & xMax, int & yMax) |
1711 | { |
1712 | xMin = yMin = xMax = yMax = INT_MIN; |
1713 | |
1714 | if (IsSpace(nGlyphId, pLoca, lLocaSize, pHead)) {return false;} |
1715 | |
1716 | void * pSimpleGlyf = GlyfLookup(nGlyphId, pGlyf, pLoca, lGlyfSize, lLocaSize, pHead); |
1717 | if (pSimpleGlyf == NULL) {return false;} |
1718 | |
1719 | return GlyfBox(pSimpleGlyf, xMin, yMin, xMax, yMax); |
1720 | } |
1721 | |
1722 | /*---------------------------------------------------------------------------------------------- |
1723 | Get the number of contours based on the given tables and Glyph ID |
1724 | Handles both simple and composite glyphs. |
1725 | Return true if successful, false otherwise. On false, cnContours will be INT_MIN |
1726 | False may indicate a white space glyph or a multi-level composite glyph. |
1727 | ----------------------------------------------------------------------------------------------*/ |
1728 | bool GlyfContourCount(gid16 nGlyphId, const void * pGlyf, const void * pLoca, |
1729 | size_t lGlyfSize, size_t lLocaSize, const void * pHead, size_t & cnContours) |
1730 | { |
1731 | cnContours = static_cast<size_t>(INT_MIN); |
1732 | |
1733 | if (IsSpace(nGlyphId, pLoca, lLocaSize, pHead)) {return false;} |
1734 | |
1735 | void * pSimpleGlyf = GlyfLookup(nGlyphId, pGlyf, pLoca, lGlyfSize, lLocaSize, pHead); |
1736 | if (pSimpleGlyf == NULL) {return false;} |
1737 | |
1738 | int cRtnContours = GlyfContourCount(pSimpleGlyf); |
1739 | if (cRtnContours >= 0) |
1740 | { |
1741 | cnContours = size_t(cRtnContours); |
1742 | return true; |
1743 | } |
1744 | |
1745 | //handle composite glyphs |
1746 | |
1747 | int rgnCompId[kMaxGlyphComponents]; // assumes no glyph will be made of more than 8 components |
1748 | size_t cCompIdTotal = kMaxGlyphComponents; |
1749 | size_t cCompId = 0; |
1750 | |
1751 | if (!GetComponentGlyphIds(pSimpleGlyf, rgnCompId, cCompIdTotal, cCompId)) |
1752 | return false; |
1753 | |
1754 | cRtnContours = 0; |
1755 | int cTmp = 0; |
1756 | for (size_t i = 0; i < cCompId; i++) |
1757 | { |
1758 | if (IsSpace(static_cast<gid16>(rgnCompId[i]), pLoca, lLocaSize, pHead)) {return false;} |
1759 | pSimpleGlyf = GlyfLookup(static_cast<gid16>(rgnCompId[i]), |
1760 | pGlyf, pLoca, lGlyfSize, lLocaSize, pHead); |
1761 | if (pSimpleGlyf == 0) {return false;} |
1762 | // return false on multi-level composite |
1763 | if ((cTmp = GlyfContourCount(pSimpleGlyf)) < 0) |
1764 | return false; |
1765 | cRtnContours += cTmp; |
1766 | } |
1767 | |
1768 | cnContours = size_t(cRtnContours); |
1769 | return true; |
1770 | } |
1771 | |
1772 | /*---------------------------------------------------------------------------------------------- |
1773 | Get the point numbers for the end points of the glyph contours based on the given tables |
1774 | and Glyph ID |
1775 | Handles both simple and composite glyphs. |
1776 | cnPoints - count of contours from GlyfContourCount (same as number of end points) |
1777 | prgnContourEndPoints - should point to a buffer large enough to hold cnPoints integers |
1778 | Return true if successful, false otherwise. On false, all end points are INT_MIN |
1779 | False may indicate a white space glyph or a multi-level composite glyph. |
1780 | ----------------------------------------------------------------------------------------------*/ |
1781 | bool GlyfContourEndPoints(gid16 nGlyphId, const void * pGlyf, const void * pLoca, |
1782 | size_t lGlyfSize, size_t lLocaSize, const void * pHead, |
1783 | int * prgnContourEndPoint, size_t cnPoints) |
1784 | { |
1785 | memset(prgnContourEndPoint, 0xFF, cnPoints * sizeof(int)); |
1786 | // std::fill_n(prgnContourEndPoint, cnPoints, INT_MIN); |
1787 | |
1788 | if (IsSpace(nGlyphId, pLoca, lLocaSize, pHead)) {return false;} |
1789 | |
1790 | void * pSimpleGlyf = GlyfLookup(nGlyphId, pGlyf, pLoca, lGlyfSize, lLocaSize, pHead); |
1791 | if (pSimpleGlyf == NULL) {return false;} |
1792 | |
1793 | int cContours = GlyfContourCount(pSimpleGlyf); |
1794 | int cActualPts = 0; |
1795 | if (cContours > 0) |
1796 | return GlyfContourEndPoints(pSimpleGlyf, prgnContourEndPoint, cnPoints, cActualPts); |
1797 | |
1798 | // handle composite glyphs |
1799 | |
1800 | int rgnCompId[kMaxGlyphComponents]; // assumes no glyph will be made of more than 8 components |
1801 | size_t cCompIdTotal = kMaxGlyphComponents; |
1802 | size_t cCompId = 0; |
1803 | |
1804 | if (!GetComponentGlyphIds(pSimpleGlyf, rgnCompId, cCompIdTotal, cCompId)) |
1805 | return false; |
1806 | |
1807 | int * prgnCurrentEndPoint = prgnContourEndPoint; |
1808 | int cCurrentPoints = cnPoints; |
1809 | int nPrevPt = 0; |
1810 | for (size_t i = 0; i < cCompId; i++) |
1811 | { |
1812 | if (IsSpace(static_cast<gid16>(rgnCompId[i]), pLoca, lLocaSize, pHead)) {return false;} |
1813 | pSimpleGlyf = GlyfLookup(static_cast<gid16>(rgnCompId[i]), pGlyf, pLoca, lGlyfSize, lLocaSize, pHead); |
1814 | if (pSimpleGlyf == NULL) {return false;} |
1815 | // returns false on multi-level composite |
1816 | if (!GlyfContourEndPoints(pSimpleGlyf, prgnCurrentEndPoint, cCurrentPoints, cActualPts)) |
1817 | return false; |
1818 | // points in composite are numbered sequentially as components are added |
1819 | // must adjust end point numbers for new point numbers |
1820 | for (int j = 0; j < cActualPts; j++) |
1821 | prgnCurrentEndPoint[j] += nPrevPt; |
1822 | nPrevPt = prgnCurrentEndPoint[cActualPts - 1] + 1; |
1823 | |
1824 | prgnCurrentEndPoint += cActualPts; |
1825 | cCurrentPoints -= cActualPts; |
1826 | } |
1827 | |
1828 | return true; |
1829 | } |
1830 | |
1831 | /*---------------------------------------------------------------------------------------------- |
1832 | Get the points for a glyph based on the given tables and Glyph ID |
1833 | Handles both simple and composite glyphs. |
1834 | cnPoints - count of points from largest end point obtained from GlyfContourEndPoints |
1835 | prgnX & prgnY - should point to buffers large enough to hold cnPoints integers |
1836 | The ranges are parallel so that coordinates for point(n) are found at offset n in |
1837 | both ranges. These points are in absolute coordinates. |
1838 | prgfOnCurve - should point to a buffer a large enough to hold cnPoints bytes (bool) |
1839 | This range is parallel to the prgnX & prgnY |
1840 | Return true if successful, false otherwise. On false, all points may be INT_MIN |
1841 | False may indicate a white space glyph, a multi-level composite, or a corrupt font |
1842 | It's not clear from the TTF spec when the transforms should be applied. Should the |
1843 | transform be done before or after attachment point calcs? (current code - before) |
1844 | Should the transform be applied to other offsets? (currently - no; however commented |
1845 | out code is in place so that if CompoundGlyph::UnscaledOffset on the MS rasterizer is |
1846 | clear (typical) then yes, and if CompoundGlyph::ScaledOffset on the Apple rasterizer is |
1847 | clear (typical?) then no). See GetComponentTransform. |
1848 | It's also unclear where point numbering with attachment poinst starts |
1849 | (currently - first point number is relative to whole glyph, second point number is |
1850 | relative to current glyph). |
1851 | ----------------------------------------------------------------------------------------------*/ |
1852 | bool GlyfPoints(gid16 nGlyphId, const void * pGlyf, |
1853 | const void * pLoca, size_t lGlyfSize, size_t lLocaSize, const void * pHead, |
1854 | const int * /*prgnContourEndPoint*/, size_t /*cnEndPoints*/, |
1855 | int * prgnX, int * prgnY, bool * prgfOnCurve, size_t cnPoints) |
1856 | { |
1857 | memset(prgnX, 0x7F, cnPoints * sizeof(int)); |
1858 | memset(prgnY, 0x7F, cnPoints * sizeof(int)); |
1859 | |
1860 | if (IsSpace(nGlyphId, pLoca, lLocaSize, pHead)) |
1861 | return false; |
1862 | |
1863 | void * pSimpleGlyf = GlyfLookup(nGlyphId, pGlyf, pLoca, lGlyfSize, lLocaSize, pHead); |
1864 | if (pSimpleGlyf == NULL) |
1865 | return false; |
1866 | |
1867 | int cContours = GlyfContourCount(pSimpleGlyf); |
1868 | int cActualPts; |
1869 | if (cContours > 0) |
1870 | { |
1871 | if (!GlyfPoints(pSimpleGlyf, prgnX, prgnY, (char *)prgfOnCurve, cnPoints, cActualPts)) |
1872 | return false; |
1873 | CalcAbsolutePoints(prgnX, prgnY, cnPoints); |
1874 | SimplifyFlags((char *)prgfOnCurve, cnPoints); |
1875 | return true; |
1876 | } |
1877 | |
1878 | // handle composite glyphs |
1879 | int rgnCompId[kMaxGlyphComponents]; // assumes no glyph will be made of more than 8 components |
1880 | size_t cCompIdTotal = kMaxGlyphComponents; |
1881 | size_t cCompId = 0; |
1882 | |
1883 | // this will fail if there are more components than there is room for |
1884 | if (!GetComponentGlyphIds(pSimpleGlyf, rgnCompId, cCompIdTotal, cCompId)) |
1885 | return false; |
1886 | |
1887 | int * prgnCurrentX = prgnX; |
1888 | int * prgnCurrentY = prgnY; |
1889 | char * prgbCurrentFlag = (char *)prgfOnCurve; // converting bool to char should be safe |
1890 | int cCurrentPoints = cnPoints; |
1891 | bool fOffset = true, fTransOff = true; |
1892 | int a, b; |
1893 | float flt11, flt12, flt21, flt22; |
1894 | // int * prgnPrevX = prgnX; // in case first att pt number relative to preceding glyph |
1895 | // int * prgnPrevY = prgnY; |
1896 | for (size_t i = 0; i < cCompId; i++) |
1897 | { |
1898 | if (IsSpace(static_cast<gid16>(rgnCompId[i]), pLoca, lLocaSize, pHead)) {return false;} |
1899 | void * pCompGlyf = GlyfLookup(static_cast<gid16>(rgnCompId[i]), pGlyf, pLoca, lGlyfSize, lLocaSize, pHead); |
1900 | if (pCompGlyf == NULL) {return false;} |
1901 | // returns false on multi-level composite |
1902 | if (!GlyfPoints(pCompGlyf, prgnCurrentX, prgnCurrentY, prgbCurrentFlag, |
1903 | cCurrentPoints, cActualPts)) |
1904 | return false; |
1905 | if (!GetComponentPlacement(pSimpleGlyf, rgnCompId[i], fOffset, a, b)) |
1906 | return false; |
1907 | if (!GetComponentTransform(pSimpleGlyf, rgnCompId[i], |
1908 | flt11, flt12, flt21, flt22, fTransOff)) |
1909 | return false; |
1910 | bool fIdTrans = flt11 == 1.0 && flt12 == 0.0 && flt21 == 0.0 && flt22 == 1.0; |
1911 | |
1912 | // convert points to absolute coordinates |
1913 | // do before transform and attachment point placement are applied |
1914 | CalcAbsolutePoints(prgnCurrentX, prgnCurrentY, cActualPts); |
1915 | |
1916 | // apply transform - see main method note above |
1917 | // do before attachment point calcs |
1918 | if (!fIdTrans) |
1919 | for (int j = 0; j < cActualPts; j++) |
1920 | { |
1921 | int x = prgnCurrentX[j]; // store before transform applied |
1922 | int y = prgnCurrentY[j]; |
1923 | prgnCurrentX[j] = (int)(x * flt11 + y * flt12); |
1924 | prgnCurrentY[j] = (int)(x * flt21 + y * flt22); |
1925 | } |
1926 | |
1927 | // apply placement - see main method note above |
1928 | int nXOff, nYOff; |
1929 | if (fOffset) // explicit x & y offsets |
1930 | { |
1931 | /* ignore fTransOff for now |
1932 | if (fTransOff && !fIdTrans) |
1933 | { // transform x & y offsets |
1934 | nXOff = (int)(a * flt11 + b * flt12); |
1935 | nYOff = (int)(a * flt21 + b * flt22); |
1936 | } |
1937 | else */ |
1938 | { // don't transform offset |
1939 | nXOff = a; |
1940 | nYOff = b; |
1941 | } |
1942 | } |
1943 | else // attachment points |
1944 | { // in case first point is relative to preceding glyph and second relative to current |
1945 | // nXOff = prgnPrevX[a] - prgnCurrentX[b]; |
1946 | // nYOff = prgnPrevY[a] - prgnCurrentY[b]; |
1947 | // first point number relative to whole composite, second relative to current glyph |
1948 | nXOff = prgnX[a] - prgnCurrentX[b]; |
1949 | nYOff = prgnY[a] - prgnCurrentY[b]; |
1950 | } |
1951 | for (int j = 0; j < cActualPts; j++) |
1952 | { |
1953 | prgnCurrentX[j] += nXOff; |
1954 | prgnCurrentY[j] += nYOff; |
1955 | } |
1956 | |
1957 | // prgnPrevX = prgnCurrentX; |
1958 | // prgnPrevY = prgnCurrentY; |
1959 | prgnCurrentX += cActualPts; |
1960 | prgnCurrentY += cActualPts; |
1961 | prgbCurrentFlag += cActualPts; |
1962 | cCurrentPoints -= cActualPts; |
1963 | } |
1964 | |
1965 | SimplifyFlags((char *)prgfOnCurve, cnPoints); |
1966 | |
1967 | return true; |
1968 | } |
1969 | |
1970 | /*---------------------------------------------------------------------------------------------- |
1971 | Simplify the meaning of flags to just indicate whether point is on-curve or off-curve. |
1972 | ---------------------------------------------------------------------------------------------*/ |
1973 | bool SimplifyFlags(char * prgbFlags, int cnPoints) |
1974 | { |
1975 | for (int i = 0; i < cnPoints; i++) |
1976 | prgbFlags[i] = static_cast<char>(prgbFlags[i] & Sfnt::SimpleGlyph::OnCurve); |
1977 | return true; |
1978 | } |
1979 | |
1980 | /*---------------------------------------------------------------------------------------------- |
1981 | Convert relative point coordinates to absolute coordinates |
1982 | Points are stored in the font such that they are offsets from one another except for the |
1983 | first point of a glyph. |
1984 | ---------------------------------------------------------------------------------------------*/ |
1985 | bool CalcAbsolutePoints(int * prgnX, int * prgnY, int cnPoints) |
1986 | { |
1987 | int nX = prgnX[0]; |
1988 | int nY = prgnY[0]; |
1989 | for (int i = 1; i < cnPoints; i++) |
1990 | { |
1991 | prgnX[i] += nX; |
1992 | nX = prgnX[i]; |
1993 | prgnY[i] += nY; |
1994 | nY = prgnY[i]; |
1995 | } |
1996 | |
1997 | return true; |
1998 | } |
1999 | #endif |
2000 | |
2001 | /*---------------------------------------------------------------------------------------------- |
2002 | Return the length of the 'name' table in bytes. |
2003 | Currently used. |
2004 | ---------------------------------------------------------------------------------------------*/ |
2005 | #if 0 |
2006 | size_t NameTableLength(const byte * pTable) |
2007 | { |
2008 | byte * pb = (const_cast<byte *>(pTable)) + 2; // skip format |
2009 | size_t cRecords = *pb++ << 8; cRecords += *pb++; |
2010 | int dbStringOffset0 = (*pb++) << 8; dbStringOffset0 += *pb++; |
2011 | int dbMaxStringOffset = 0; |
2012 | for (size_t irec = 0; irec < cRecords; irec++) |
2013 | { |
2014 | int nPlatform = (*pb++) << 8; nPlatform += *pb++; |
2015 | int nEncoding = (*pb++) << 8; nEncoding += *pb++; |
2016 | int nLanguage = (*pb++) << 8; nLanguage += *pb++; |
2017 | int nName = (*pb++) << 8; nName += *pb++; |
2018 | int cbStringLen = (*pb++) << 8; cbStringLen += *pb++; |
2019 | int dbStringOffset = (*pb++) << 8; dbStringOffset += *pb++; |
2020 | if (dbMaxStringOffset < dbStringOffset + cbStringLen) |
2021 | dbMaxStringOffset = dbStringOffset + cbStringLen; |
2022 | } |
2023 | return dbStringOffset0 + dbMaxStringOffset; |
2024 | } |
2025 | #endif |
2026 | |
2027 | } // end of namespace TtfUtil |
2028 | } // end of namespace graphite |
2029 | |