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