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