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