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