/work/workdir/UnpackedTarball/graphite/src/TtfUtil.cpp
Line | Count | Source |
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 GetHeaderInfo(size_t & lOffset, size_t & lSize) |
132 | 0 | { |
133 | 0 | lOffset = 0; |
134 | 0 | lSize = offsetof(Sfnt::OffsetSubTable, table_directory); |
135 | 0 | assert(sizeof(uint32) + 4*sizeof (uint16) == lSize); |
136 | 0 | return true; |
137 | 0 | } |
138 | | |
139 | | /*---------------------------------------------------------------------------------------------- |
140 | | Check the offset table for expected data. |
141 | | Return true if success, false otherwise. |
142 | | ----------------------------------------------------------------------------------------------*/ |
143 | | bool CheckHeader(const void * pHdr) |
144 | 0 | { |
145 | 0 | const Sfnt::OffsetSubTable * pOffsetTable |
146 | 0 | = reinterpret_cast<const Sfnt::OffsetSubTable *>(pHdr); |
147 | |
|
148 | 0 | return pHdr && be::swap(pOffsetTable->scaler_type) == Sfnt::OffsetSubTable::TrueTypeWin; |
149 | 0 | } |
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 | 0 | { |
157 | 0 | const Sfnt::OffsetSubTable * pOffsetTable |
158 | 0 | = reinterpret_cast<const Sfnt::OffsetSubTable *>(pHdr); |
159 | |
|
160 | 0 | lOffset = offsetof(Sfnt::OffsetSubTable, table_directory); |
161 | 0 | lSize = be::swap(pOffsetTable->num_tables) |
162 | 0 | * sizeof(Sfnt::OffsetSubTable::Entry); |
163 | |
|
164 | 0 | return true; |
165 | 0 | } |
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 | 0 | { |
175 | 0 | const Sfnt::OffsetSubTable * pOffsetTable |
176 | 0 | = reinterpret_cast<const Sfnt::OffsetSubTable *>(pHdr); |
177 | 0 | const size_t num_tables = be::swap(pOffsetTable->num_tables); |
178 | 0 | const Sfnt::OffsetSubTable::Entry |
179 | 0 | * entry_itr = reinterpret_cast<const Sfnt::OffsetSubTable::Entry *>( |
180 | 0 | pTableDir), |
181 | 0 | * const dir_end = entry_itr + num_tables; |
182 | |
|
183 | 0 | if (num_tables > 40) |
184 | 0 | return false; |
185 | | |
186 | 0 | for (;entry_itr != dir_end; ++entry_itr) // 40 - safe guard |
187 | 0 | { |
188 | 0 | if (be::swap(entry_itr->tag) == TableTag) |
189 | 0 | { |
190 | 0 | lOffset = be::swap(entry_itr->offset); |
191 | 0 | lSize = be::swap(entry_itr->length); |
192 | 0 | return true; |
193 | 0 | } |
194 | 0 | } |
195 | | |
196 | 0 | return false; |
197 | 0 | } |
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 | 0 | { |
205 | 0 | using namespace Sfnt; |
206 | |
|
207 | 0 | if (pTable == 0 || lTableSize < 4) return false; |
208 | | |
209 | 0 | switch(TableId) |
210 | 0 | { |
211 | 0 | case Tag::cmap: // cmap |
212 | 0 | { |
213 | 0 | const Sfnt::CharacterCodeMap * const pCmap |
214 | 0 | = reinterpret_cast<const Sfnt::CharacterCodeMap *>(pTable); |
215 | 0 | if (lTableSize < sizeof(Sfnt::CharacterCodeMap)) |
216 | 0 | return false; |
217 | 0 | return be::swap(pCmap->version) == 0; |
218 | 0 | } |
219 | | |
220 | 0 | case Tag::head: // head |
221 | 0 | { |
222 | 0 | const Sfnt::FontHeader * const pHead |
223 | 0 | = reinterpret_cast<const Sfnt::FontHeader *>(pTable); |
224 | 0 | if (lTableSize < sizeof(Sfnt::FontHeader)) |
225 | 0 | return false; |
226 | 0 | bool r = be::swap(pHead->version) == OneFix |
227 | 0 | && be::swap(pHead->magic_number) == FontHeader::MagicNumber |
228 | 0 | && be::swap(pHead->glyph_data_format) |
229 | 0 | == FontHeader::GlypDataFormat |
230 | 0 | && (be::swap(pHead->index_to_loc_format) |
231 | 0 | == FontHeader::ShortIndexLocFormat |
232 | 0 | || be::swap(pHead->index_to_loc_format) |
233 | 0 | == FontHeader::LongIndexLocFormat) |
234 | 0 | && sizeof(FontHeader) <= lTableSize; |
235 | 0 | return r; |
236 | 0 | } |
237 | | |
238 | 0 | case Tag::post: // post |
239 | 0 | { |
240 | 0 | const Sfnt::PostScriptGlyphName * const pPost |
241 | 0 | = reinterpret_cast<const Sfnt::PostScriptGlyphName *>(pTable); |
242 | 0 | if (lTableSize < sizeof(Sfnt::PostScriptGlyphName)) |
243 | 0 | return false; |
244 | 0 | const fixed format = be::swap(pPost->format); |
245 | 0 | bool r = format == PostScriptGlyphName::Format1 |
246 | 0 | || format == PostScriptGlyphName::Format2 |
247 | 0 | || format == PostScriptGlyphName::Format3 |
248 | 0 | || format == PostScriptGlyphName::Format25; |
249 | 0 | return r; |
250 | 0 | } |
251 | | |
252 | 0 | case Tag::hhea: // hhea |
253 | 0 | { |
254 | 0 | const Sfnt::HorizontalHeader * pHhea = |
255 | 0 | reinterpret_cast<const Sfnt::HorizontalHeader *>(pTable); |
256 | 0 | if (lTableSize < sizeof(Sfnt::HorizontalHeader)) |
257 | 0 | return false; |
258 | 0 | bool r = be::swap(pHhea->version) == OneFix |
259 | 0 | && be::swap(pHhea->metric_data_format) == 0 |
260 | 0 | && sizeof (Sfnt::HorizontalHeader) <= lTableSize; |
261 | 0 | return r; |
262 | 0 | } |
263 | | |
264 | 0 | case Tag::maxp: // maxp |
265 | 0 | { |
266 | 0 | const Sfnt::MaximumProfile * pMaxp = |
267 | 0 | reinterpret_cast<const Sfnt::MaximumProfile *>(pTable); |
268 | 0 | if (lTableSize < sizeof(Sfnt::MaximumProfile)) |
269 | 0 | return false; |
270 | 0 | bool r = be::swap(pMaxp->version) == OneFix |
271 | 0 | && sizeof(Sfnt::MaximumProfile) <= lTableSize; |
272 | 0 | return r; |
273 | 0 | } |
274 | | |
275 | 0 | case Tag::OS_2: // OS/2 |
276 | 0 | { |
277 | 0 | const Sfnt::Compatibility * pOs2 |
278 | 0 | = reinterpret_cast<const Sfnt::Compatibility *>(pTable); |
279 | 0 | if (be::swap(pOs2->version) == 0) |
280 | 0 | { // OS/2 table version 1 size |
281 | | // if (sizeof(Sfnt::Compatibility) |
282 | | // - sizeof(uint32)*2 - sizeof(int16)*2 |
283 | | // - sizeof(uint16)*3 <= lTableSize) |
284 | 0 | if (sizeof(Sfnt::Compatibility0) <= lTableSize) |
285 | 0 | return true; |
286 | 0 | } |
287 | 0 | else if (be::swap(pOs2->version) == 1) |
288 | 0 | { // OS/2 table version 2 size |
289 | | // if (sizeof(Sfnt::Compatibility) |
290 | | // - sizeof(int16) *2 |
291 | | // - sizeof(uint16)*3 <= lTableSize) |
292 | 0 | if (sizeof(Sfnt::Compatibility1) <= lTableSize) |
293 | 0 | return true; |
294 | 0 | } |
295 | 0 | else if (be::swap(pOs2->version) == 2) |
296 | 0 | { // OS/2 table version 3 size |
297 | 0 | if (sizeof(Sfnt::Compatibility2) <= lTableSize) |
298 | 0 | return true; |
299 | 0 | } |
300 | 0 | else if (be::swap(pOs2->version) == 3 || be::swap(pOs2->version) == 4) |
301 | 0 | { // OS/2 table version 4 size - version 4 changed the meaning of some fields which we don't use |
302 | 0 | if (sizeof(Sfnt::Compatibility3) <= lTableSize) |
303 | 0 | return true; |
304 | 0 | } |
305 | 0 | else |
306 | 0 | return false; |
307 | 0 | break; |
308 | 0 | } |
309 | | |
310 | 0 | case Tag::name: |
311 | 0 | { |
312 | 0 | const Sfnt::FontNames * pName |
313 | 0 | = reinterpret_cast<const Sfnt::FontNames *>(pTable); |
314 | 0 | if (lTableSize < sizeof(Sfnt::FontNames)) |
315 | 0 | return false; |
316 | 0 | return be::swap(pName->format) == 0; |
317 | 0 | } |
318 | | |
319 | 0 | case Tag::glyf: |
320 | 0 | { |
321 | 0 | return (lTableSize >= sizeof(Sfnt::Glyph)); |
322 | 0 | } |
323 | | |
324 | 0 | default: |
325 | 0 | break; |
326 | 0 | } |
327 | | |
328 | 0 | return true; |
329 | 0 | } |
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 | 0 | { |
338 | 0 | const Sfnt::MaximumProfile * pTable = |
339 | 0 | reinterpret_cast<const Sfnt::MaximumProfile *>(pMaxp); |
340 | 0 | return be::swap(pTable->num_glyphs); |
341 | 0 | } |
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 | 0 | { |
402 | 0 | const Sfnt::FontHeader * pTable = |
403 | 0 | reinterpret_cast<const Sfnt::FontHeader *>(pHead); |
404 | |
|
405 | 0 | return be::swap(pTable->units_per_em); |
406 | 0 | } |
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 | 0 | { |
507 | 0 | lOffset = 0; |
508 | 0 | lSize = 0; |
509 | |
|
510 | 0 | const Sfnt::FontNames * pTable = reinterpret_cast<const Sfnt::FontNames *>(pName); |
511 | 0 | uint16 cRecord = be::swap(pTable->count); |
512 | 0 | uint16 nRecordOffset = be::swap(pTable->string_offset); |
513 | 0 | const Sfnt::NameRecord * pRecord = reinterpret_cast<const Sfnt::NameRecord *>(pTable + 1); |
514 | |
|
515 | 0 | for (int i = 0; i < cRecord; ++i) |
516 | 0 | { |
517 | 0 | if (be::swap(pRecord->platform_id) == nPlatformId && |
518 | 0 | be::swap(pRecord->platform_specific_id) == nEncodingId && |
519 | 0 | be::swap(pRecord->language_id) == nLangId && |
520 | 0 | be::swap(pRecord->name_id) == nNameId) |
521 | 0 | { |
522 | 0 | lOffset = be::swap(pRecord->offset) + nRecordOffset; |
523 | 0 | lSize = be::swap(pRecord->length); |
524 | 0 | return true; |
525 | 0 | } |
526 | 0 | pRecord++; |
527 | 0 | } |
528 | | |
529 | 0 | return false; |
530 | 0 | } |
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 | 0 | { |
784 | 0 | const Sfnt::HorizontalMetric * phmtx = |
785 | 0 | reinterpret_cast<const Sfnt::HorizontalMetric *>(pHmtx); |
786 | |
|
787 | 0 | const Sfnt::HorizontalHeader * phhea = |
788 | 0 | reinterpret_cast<const Sfnt::HorizontalHeader *>(pHhea); |
789 | |
|
790 | 0 | size_t cLongHorMetrics = be::swap(phhea->num_long_hor_metrics); |
791 | 0 | if (nGlyphId < cLongHorMetrics) |
792 | 0 | { // glyph id is acceptable |
793 | 0 | if ((nGlyphId + 1) * sizeof(Sfnt::HorizontalMetric) > lHmtxSize) return false; |
794 | 0 | nAdvWid = be::swap(phmtx[nGlyphId].advance_width); |
795 | 0 | nLsb = be::swap(phmtx[nGlyphId].left_side_bearing); |
796 | 0 | } |
797 | 0 | else |
798 | 0 | { |
799 | | // guard against bad glyph id |
800 | 0 | size_t lLsbOffset = sizeof(Sfnt::HorizontalMetric) * cLongHorMetrics + |
801 | 0 | sizeof(int16) * (nGlyphId - cLongHorMetrics); // offset in bytes |
802 | | // We test like this as LsbOffset is an offset not a length. |
803 | 0 | if (lLsbOffset >= lHmtxSize - sizeof(int16) || cLongHorMetrics == 0) |
804 | 0 | { |
805 | 0 | nLsb = 0; |
806 | 0 | return false; |
807 | 0 | } |
808 | 0 | nAdvWid = be::swap(phmtx[cLongHorMetrics - 1].advance_width); |
809 | 0 | nLsb = be::peek<int16>(reinterpret_cast<const byte *>(phmtx) + lLsbOffset); |
810 | 0 | } |
811 | | |
812 | 0 | return true; |
813 | 0 | } |
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 | 0 | { |
822 | 0 | const Sfnt::CharacterCodeMap * pTable = reinterpret_cast<const Sfnt::CharacterCodeMap *>(pCmap); |
823 | 0 | uint16 csuPlatforms = be::swap(pTable->num_subtables); |
824 | 0 | if (length && (sizeof(Sfnt::CharacterCodeMap) + 8 * (csuPlatforms - 1) > length)) |
825 | 0 | return NULL; |
826 | 0 | for (int i = 0; i < csuPlatforms; i++) |
827 | 0 | { |
828 | 0 | if (be::swap(pTable->encoding[i].platform_id) == nPlatformId && |
829 | 0 | (nEncodingId == -1 || be::swap(pTable->encoding[i].platform_specific_id) == nEncodingId)) |
830 | 0 | { |
831 | 0 | uint32 offset = be::swap(pTable->encoding[i].offset); |
832 | 0 | const uint8 * pRtn = reinterpret_cast<const uint8 *>(pCmap) + offset; |
833 | 0 | if (length) |
834 | 0 | { |
835 | 0 | if (offset > length - 2) return NULL; |
836 | 0 | uint16 format = be::read<uint16>(pRtn); |
837 | 0 | if (format == 4) |
838 | 0 | { |
839 | 0 | if (offset > length - 4) return NULL; |
840 | 0 | uint16 subTableLength = be::peek<uint16>(pRtn); |
841 | 0 | if (i + 1 == csuPlatforms) |
842 | 0 | { |
843 | 0 | if (subTableLength > length - offset) |
844 | 0 | return NULL; |
845 | 0 | } |
846 | 0 | else if (subTableLength > be::swap(pTable->encoding[i+1].offset)) |
847 | 0 | return NULL; |
848 | 0 | } |
849 | 0 | if (format == 12) |
850 | 0 | { |
851 | 0 | if (offset > length - 6) return NULL; |
852 | 0 | uint32 subTableLength = be::peek<uint32>(pRtn); |
853 | 0 | if (i + 1 == csuPlatforms) |
854 | 0 | { |
855 | 0 | if (subTableLength > length - offset) |
856 | 0 | return NULL; |
857 | 0 | } |
858 | 0 | else if (subTableLength > be::swap(pTable->encoding[i+1].offset)) |
859 | 0 | return NULL; |
860 | 0 | } |
861 | 0 | } |
862 | 0 | return reinterpret_cast<const uint8 *>(pCmap) + offset; |
863 | 0 | } |
864 | 0 | } |
865 | | |
866 | 0 | return 0; |
867 | 0 | } |
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 | 0 | { |
874 | 0 | size_t table_len = (const byte *)pCmapEnd - (const byte *)pCmapSubtable4; |
875 | 0 | if (!pCmapSubtable4) return false; |
876 | 0 | 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 | 0 | if (table_len < sizeof(*pTable) || be::swap(pTable->format) != 4) return false; |
880 | 0 | const Sfnt::CmapSubTableFormat4 * pTable4 = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmapSubtable4); |
881 | 0 | if (table_len < sizeof(*pTable4)) |
882 | 0 | return false; |
883 | 0 | uint16 length = be::swap(pTable4->length); |
884 | 0 | if (length > table_len) |
885 | 0 | return false; |
886 | 0 | if (length < sizeof(Sfnt::CmapSubTableFormat4)) |
887 | 0 | return false; |
888 | 0 | uint16 nRanges = be::swap(pTable4->seg_count_x2) >> 1; |
889 | 0 | if (!nRanges || length < sizeof(Sfnt::CmapSubTableFormat4) + 4 * nRanges * sizeof(uint16)) |
890 | 0 | return false; |
891 | | // check last range is properly terminated |
892 | 0 | uint16 chEnd = be::peek<uint16>(pTable4->end_code + nRanges - 1); |
893 | 0 | if (chEnd != 0xFFFF) |
894 | 0 | 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 | 0 | return true; |
924 | 0 | } |
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 | 0 | { |
933 | 0 | const Sfnt::CmapSubTableFormat4 * pTable = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmapSubtabel4); |
934 | |
|
935 | 0 | uint16 nSeg = be::swap(pTable->seg_count_x2) >> 1; |
936 | |
|
937 | 0 | uint16 n; |
938 | 0 | const uint16 * pLeft, * pMid; |
939 | 0 | uint16 cMid, chStart, chEnd; |
940 | |
|
941 | 0 | if (rangeKey) |
942 | 0 | { |
943 | 0 | pMid = &(pTable->end_code[rangeKey]); |
944 | 0 | chEnd = be::peek<uint16>(pMid); |
945 | 0 | } |
946 | 0 | else |
947 | 0 | { |
948 | | // Binary search of the endCode[] array |
949 | 0 | pLeft = &(pTable->end_code[0]); |
950 | 0 | n = nSeg; |
951 | 0 | while (n > 0) |
952 | 0 | { |
953 | 0 | cMid = n >> 1; // Pick an element in the middle |
954 | 0 | pMid = pLeft + cMid; |
955 | 0 | chEnd = be::peek<uint16>(pMid); |
956 | 0 | if (nUnicodeId <= chEnd) |
957 | 0 | { |
958 | 0 | if (cMid == 0 || nUnicodeId > be::peek<uint16>(pMid -1)) |
959 | 0 | break; // Must be this seg or none! |
960 | 0 | n = cMid; // Continue on left side, omitting mid point |
961 | 0 | } |
962 | 0 | else |
963 | 0 | { |
964 | 0 | pLeft = pMid + 1; // Continue on right side, omitting mid point |
965 | 0 | n -= (cMid + 1); |
966 | 0 | } |
967 | 0 | } |
968 | |
|
969 | 0 | if (!n) |
970 | 0 | return 0; |
971 | 0 | } |
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 | 0 | chStart = be::peek<uint16>(pMid += nSeg + 1); |
977 | 0 | if (chEnd >= nUnicodeId && nUnicodeId >= chStart) |
978 | 0 | { |
979 | | // Found correct segment. Find Glyph Id |
980 | 0 | int16 idDelta = be::peek<uint16>(pMid += nSeg); |
981 | 0 | uint16 idRangeOffset = be::peek<uint16>(pMid += nSeg); |
982 | |
|
983 | 0 | if (idRangeOffset == 0) |
984 | 0 | return (uint16)(idDelta + nUnicodeId); // must use modulus 2^16 |
985 | | |
986 | | // Look up value in glyphIdArray |
987 | 0 | const ptrdiff_t offset = (nUnicodeId - chStart) + (idRangeOffset >> 1) + |
988 | 0 | (pMid - reinterpret_cast<const uint16 *>(pTable)); |
989 | 0 | if (offset * 2 + 1 >= be::swap<uint16>(pTable->length)) |
990 | 0 | return 0; |
991 | 0 | gid16 nGlyphId = be::peek<uint16>(reinterpret_cast<const uint16 *>(pTable)+offset); |
992 | | // If this value is 0, return 0. Else add the idDelta |
993 | 0 | return nGlyphId ? nGlyphId + idDelta : 0; |
994 | 0 | } |
995 | | |
996 | 0 | return 0; |
997 | 0 | } |
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 | 0 | { |
1007 | 0 | const Sfnt::CmapSubTableFormat4 * pTable = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmap31); |
1008 | |
|
1009 | 0 | uint16 nRange = be::swap(pTable->seg_count_x2) >> 1; |
1010 | |
|
1011 | 0 | uint32 nUnicodePrev = (uint32)nUnicodeId; |
1012 | |
|
1013 | 0 | const uint16 * pStartCode = &(pTable->end_code[0]) |
1014 | 0 | + nRange // length of end code array |
1015 | 0 | + 1; // reserved word |
1016 | |
|
1017 | 0 | if (nUnicodePrev == 0) |
1018 | 0 | { |
1019 | | // return the first codepoint. |
1020 | 0 | if (pRangeKey) |
1021 | 0 | *pRangeKey = 0; |
1022 | 0 | return be::peek<uint16>(pStartCode); |
1023 | 0 | } |
1024 | 0 | else if (nUnicodePrev >= 0xFFFF) |
1025 | 0 | { |
1026 | 0 | if (pRangeKey) |
1027 | 0 | *pRangeKey = nRange - 1; |
1028 | 0 | return 0xFFFF; |
1029 | 0 | } |
1030 | | |
1031 | 0 | int iRange = (pRangeKey) ? *pRangeKey : 0; |
1032 | | // Just in case we have a bad key: |
1033 | 0 | while (iRange > 0 && be::peek<uint16>(pStartCode + iRange) > nUnicodePrev) |
1034 | 0 | iRange--; |
1035 | 0 | while (iRange < nRange - 1 && be::peek<uint16>(pTable->end_code + iRange) < nUnicodePrev) |
1036 | 0 | iRange++; |
1037 | | |
1038 | | // Now iRange is the range containing nUnicodePrev. |
1039 | 0 | unsigned int nStartCode = be::peek<uint16>(pStartCode + iRange); |
1040 | 0 | unsigned int nEndCode = be::peek<uint16>(pTable->end_code + iRange); |
1041 | |
|
1042 | 0 | if (nStartCode > nUnicodePrev) |
1043 | | // Oops, nUnicodePrev is not in the cmap! Adjust so we get a reasonable |
1044 | | // answer this time around. |
1045 | 0 | nUnicodePrev = nStartCode - 1; |
1046 | |
|
1047 | 0 | if (nEndCode > nUnicodePrev) |
1048 | 0 | { |
1049 | | // Next is in the same range; it is the next successive codepoint. |
1050 | 0 | if (pRangeKey) |
1051 | 0 | *pRangeKey = iRange; |
1052 | 0 | return nUnicodePrev + 1; |
1053 | 0 | } |
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 | 0 | if (pRangeKey) |
1059 | 0 | *pRangeKey = iRange + 1; |
1060 | 0 | return (iRange + 1 >= nRange) ? 0xFFFF : be::peek<uint16>(pStartCode + iRange + 1); |
1061 | 0 | } |
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 | 0 | { |
1068 | 0 | size_t table_len = (const byte *)pCmapEnd - (const byte *)pCmapSubtable12; |
1069 | 0 | if (!pCmapSubtable12) return false; |
1070 | 0 | const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable12); |
1071 | 0 | if (table_len < sizeof(*pTable) || be::swap(pTable->format) != 12) |
1072 | 0 | return false; |
1073 | 0 | const Sfnt::CmapSubTableFormat12 * pTable12 = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmapSubtable12); |
1074 | 0 | if (table_len < sizeof(*pTable12)) |
1075 | 0 | return false; |
1076 | 0 | uint32 length = be::swap(pTable12->length); |
1077 | 0 | if (length > table_len) |
1078 | 0 | return false; |
1079 | 0 | if (length < sizeof(Sfnt::CmapSubTableFormat12)) |
1080 | 0 | return false; |
1081 | 0 | uint32 num_groups = be::swap(pTable12->num_groups); |
1082 | 0 | if (num_groups > 0x10000000 || length != (sizeof(Sfnt::CmapSubTableFormat12) + (num_groups - 1) * sizeof(uint32) * 3)) |
1083 | 0 | 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 | 0 | return true; |
1094 | 0 | } |
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 | 0 | { |
1103 | 0 | 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 | 0 | uint32 ucGroups = be::swap(pTable->num_groups); |
1107 | |
|
1108 | 0 | for (unsigned int i = rangeKey; i < ucGroups; i++) |
1109 | 0 | { |
1110 | 0 | uint32 uStartCode = be::swap(pTable->group[i].start_char_code); |
1111 | 0 | uint32 uEndCode = be::swap(pTable->group[i].end_char_code); |
1112 | 0 | if (uUnicodeId >= uStartCode && uUnicodeId <= uEndCode) |
1113 | 0 | { |
1114 | 0 | uint32 uDiff = uUnicodeId - uStartCode; |
1115 | 0 | uint32 uStartGid = be::swap(pTable->group[i].start_glyph_id); |
1116 | 0 | return static_cast<gid16>(uStartGid + uDiff); |
1117 | 0 | } |
1118 | 0 | } |
1119 | | |
1120 | 0 | return 0; |
1121 | 0 | } |
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 | 0 | { |
1131 | 0 | const Sfnt::CmapSubTableFormat12 * pTable = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmap310); |
1132 | |
|
1133 | 0 | int nRange = be::swap(pTable->num_groups); |
1134 | |
|
1135 | 0 | uint32 nUnicodePrev = (uint32)nUnicodeId; |
1136 | |
|
1137 | 0 | if (nUnicodePrev == 0) |
1138 | 0 | { |
1139 | | // return the first codepoint. |
1140 | 0 | if (pRangeKey) |
1141 | 0 | *pRangeKey = 0; |
1142 | 0 | return be::swap(pTable->group[0].start_char_code); |
1143 | 0 | } |
1144 | 0 | else if (nUnicodePrev >= 0x10FFFF) |
1145 | 0 | { |
1146 | 0 | if (pRangeKey) |
1147 | 0 | *pRangeKey = nRange; |
1148 | 0 | return 0x10FFFF; |
1149 | 0 | } |
1150 | | |
1151 | 0 | int iRange = (pRangeKey) ? *pRangeKey : 0; |
1152 | | // Just in case we have a bad key: |
1153 | 0 | while (iRange > 0 && be::swap(pTable->group[iRange].start_char_code) > nUnicodePrev) |
1154 | 0 | iRange--; |
1155 | 0 | while (iRange < nRange - 1 && be::swap(pTable->group[iRange].end_char_code) < nUnicodePrev) |
1156 | 0 | iRange++; |
1157 | | |
1158 | | // Now iRange is the range containing nUnicodePrev. |
1159 | |
|
1160 | 0 | unsigned int nStartCode = be::swap(pTable->group[iRange].start_char_code); |
1161 | 0 | unsigned int nEndCode = be::swap(pTable->group[iRange].end_char_code); |
1162 | |
|
1163 | 0 | if (nStartCode > nUnicodePrev) |
1164 | | // Oops, nUnicodePrev is not in the cmap! Adjust so we get a reasonable |
1165 | | // answer this time around. |
1166 | 0 | nUnicodePrev = nStartCode - 1; |
1167 | |
|
1168 | 0 | if (nEndCode > nUnicodePrev) |
1169 | 0 | { |
1170 | | // Next is in the same range; it is the next successive codepoint. |
1171 | 0 | if (pRangeKey) |
1172 | 0 | *pRangeKey = iRange; |
1173 | 0 | return nUnicodePrev + 1; |
1174 | 0 | } |
1175 | | |
1176 | | // Otherwise the next codepoint is the first one in the next range, or 10FFFF if we're done. |
1177 | 0 | if (pRangeKey) |
1178 | 0 | *pRangeKey = iRange + 1; |
1179 | 0 | return (iRange + 1 >= nRange) ? 0x10FFFF : be::swap(pTable->group[iRange + 1].start_char_code); |
1180 | 0 | } |
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 | 0 | { |
1193 | 0 | const Sfnt::FontHeader * pTable = reinterpret_cast<const Sfnt::FontHeader *>(pHead); |
1194 | 0 | size_t res = -2; |
1195 | | |
1196 | | // CheckTable verifies the index_to_loc_format is valid |
1197 | 0 | if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::ShortIndexLocFormat) |
1198 | 0 | { // loca entries are two bytes and have been divided by two |
1199 | 0 | if (lLocaSize > 1 && nGlyphId + 1u < lLocaSize >> 1) // allow sentinel value to be accessed |
1200 | 0 | { |
1201 | 0 | const uint16 * pShortTable = reinterpret_cast<const uint16 *>(pLoca); |
1202 | 0 | res = be::peek<uint16>(pShortTable + nGlyphId) << 1; |
1203 | 0 | if (res == static_cast<size_t>(be::peek<uint16>(pShortTable + nGlyphId + 1) << 1)) |
1204 | 0 | return -1; |
1205 | 0 | } |
1206 | 0 | } |
1207 | 0 | else if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::LongIndexLocFormat) |
1208 | 0 | { // loca entries are four bytes |
1209 | 0 | if (lLocaSize > 3 && nGlyphId + 1u < lLocaSize >> 2) |
1210 | 0 | { |
1211 | 0 | const uint32 * pLongTable = reinterpret_cast<const uint32 *>(pLoca); |
1212 | 0 | res = be::peek<uint32>(pLongTable + nGlyphId); |
1213 | 0 | if (res == static_cast<size_t>(be::peek<uint32>(pLongTable + nGlyphId + 1))) |
1214 | 0 | return -1; |
1215 | 0 | } |
1216 | 0 | } |
1217 | | |
1218 | | // only get here if glyph id was bad |
1219 | 0 | return res; |
1220 | | //throw std::out_of_range("glyph id out of range for font"); |
1221 | 0 | } |
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 | 0 | { |
1229 | 0 | const uint8 * pByte = reinterpret_cast<const uint8 *>(pGlyf); |
1230 | 0 | if (OVERFLOW_OFFSET_CHECK(pByte, nGlyfOffset) || nGlyfOffset >= nTableLen - sizeof(Sfnt::Glyph)) |
1231 | 0 | return NULL; |
1232 | 0 | return const_cast<uint8 *>(pByte + nGlyfOffset); |
1233 | 0 | } |
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 | 0 | { |
1242 | 0 | const Sfnt::Glyph * pGlyph = reinterpret_cast<const Sfnt::Glyph *>(pSimpleGlyf); |
1243 | |
|
1244 | 0 | xMin = be::swap(pGlyph->x_min); |
1245 | 0 | yMin = be::swap(pGlyph->y_min); |
1246 | 0 | xMax = be::swap(pGlyph->x_max); |
1247 | 0 | yMax = be::swap(pGlyph->y_max); |
1248 | |
|
1249 | 0 | return true; |
1250 | 0 | } |
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 | 0 | { |
1625 | | // test for valid glyph id |
1626 | | // CheckTable verifies the index_to_loc_format is valid |
1627 | |
|
1628 | 0 | const Sfnt::FontHeader * pTable |
1629 | 0 | = reinterpret_cast<const Sfnt::FontHeader *>(pHead); |
1630 | |
|
1631 | 0 | if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::ShortIndexLocFormat) |
1632 | 0 | { // loca entries are two bytes (and have been divided by two) |
1633 | 0 | if (nGlyphId >= (lLocaSize >> 1) - 1) // don't allow nGlyphId to access sentinel |
1634 | 0 | { |
1635 | | // throw std::out_of_range("glyph id out of range for font"); |
1636 | 0 | return NULL; |
1637 | 0 | } |
1638 | 0 | } |
1639 | 0 | if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::LongIndexLocFormat) |
1640 | 0 | { // loca entries are four bytes |
1641 | 0 | if (nGlyphId >= (lLocaSize >> 2) - 1) |
1642 | 0 | { |
1643 | | // throw std::out_of_range("glyph id out of range for font"); |
1644 | 0 | return NULL; |
1645 | 0 | } |
1646 | 0 | } |
1647 | | |
1648 | 0 | size_t lGlyfOffset = LocaLookup(nGlyphId, pLoca, lLocaSize, pHead); |
1649 | 0 | void * pSimpleGlyf = GlyfLookup(pGlyf, lGlyfOffset, lGlyfSize); // invalid loca offset returns null |
1650 | 0 | return pSimpleGlyf; |
1651 | 0 | } |
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 |