1 /* 2 ******************************************************************************* 3 * 4 * Copyright (C) 2016 and later: Unicode, Inc. and others. 5 * License & terms of use: http://www.unicode.org/copyright.html#License 6 * 7 ******************************************************************************* 8 ******************************************************************************* 9 * 10 * Copyright (C) 1999-2013, International Business Machines 11 * Corporation and others. All Rights Reserved. 12 * 13 ******************************************************************************* 14 * file name: PortableFontInstance.cpp 15 * 16 * created on: 11/22/1999 17 * created by: Eric R. Mader 18 */ 19 20 #include <stdio.h> 21 22 #include "layout/LETypes.h" 23 #include "layout/LEFontInstance.h" 24 #include "layout/LESwaps.h" 25 26 #include "PortableFontInstance.h" 27 28 //#include "letest.h" 29 #include "sfnt.h" 30 31 #include <string.h> 32 #include <stdio.h> 33 34 #if 0 35 static const char *letagToStr(LETag tag, char *str) { 36 str[0]= 0xFF & (tag>>24); 37 str[1]= 0xFF & (tag>>16); 38 str[2]= 0xFF & (tag>>8); 39 str[3]= 0xFF & (tag>>0); 40 str[4]= 0; 41 return str; 42 } 43 #endif 44 45 // 46 // Finds the high bit by binary searching 47 // through the bits in n. 48 // 49 le_int8 PortableFontInstance::highBit(le_int32 value) 50 { 51 if (value <= 0) { 52 return -32; 53 } 54 55 le_uint8 bit = 0; 56 57 if (value >= 1 << 16) { 58 value >>= 16; 59 bit += 16; 60 } 61 62 if (value >= 1 << 8) { 63 value >>= 8; 64 bit += 8; 65 } 66 67 if (value >= 1 << 4) { 68 value >>= 4; 69 bit += 4; 70 } 71 72 if (value >= 1 << 2) { 73 value >>= 2; 74 bit += 2; 75 } 76 77 if (value >= 1 << 1) { 78 value >>= 1; 79 bit += 1; 80 } 81 82 return bit; 83 } 84 85 PortableFontInstance::PortableFontInstance(const char *fileName, float pointSize, LEErrorCode &status) 86 : fFile(NULL), fPointSize(pointSize), fUnitsPerEM(0), fFontChecksum(0), fAscent(0), fDescent(0), fLeading(0), 87 fDirectory(NULL), fNAMETable(NULL), fNameCount(0), fNameStringOffset(0), fCMAPMapper(NULL), fHMTXTable(NULL), fNumGlyphs(0), fNumLongHorMetrics(0) 88 { 89 if (LE_FAILURE(status)) { 90 return; 91 } 92 93 // open the font file 94 fFile = fopen(fileName, "rb"); 95 //printf("Open Font: %s\n", fileName); 96 97 if (fFile == NULL) { 98 printf("%s:%d: %s: FNF\n", __FILE__, __LINE__, fileName); 99 status = LE_FONT_FILE_NOT_FOUND_ERROR; 100 return; 101 } 102 103 // read in the directory 104 SFNTDirectory tempDir; 105 106 fread(&tempDir, sizeof tempDir, 1, fFile); 107 108 le_int32 dirSize = sizeof tempDir + ((SWAPW(tempDir.numTables) - ANY_NUMBER) * sizeof(DirectoryEntry)); 109 const LETag headTag = LE_HEAD_TABLE_TAG; 110 const LETag hheaTag = LE_HHEA_TABLE_TAG; 111 const HEADTable *headTable = NULL; 112 const HHEATable *hheaTable = NULL; 113 // const NAMETable *nameTable = NULL; 114 le_uint16 numTables = 0; 115 116 fDirectory = (const SFNTDirectory *) LE_NEW_ARRAY(char, dirSize); 117 118 if (fDirectory == NULL) { 119 printf("%s:%d: %s: malloc err\n", __FILE__, __LINE__, fileName); 120 status = LE_MEMORY_ALLOCATION_ERROR; 121 goto error_exit; 122 } 123 124 fseek(fFile, 0L, SEEK_SET); 125 fread((void *) fDirectory, sizeof(char), dirSize, fFile); 126 127 // 128 // We calculate these numbers 'cause some fonts 129 // have bogus values for them in the directory header. 130 // 131 numTables = SWAPW(fDirectory->numTables); 132 fDirPower = 1 << highBit(numTables); 133 fDirExtra = numTables - fDirPower; 134 135 // read unitsPerEm from 'head' table 136 headTable = (const HEADTable *) readFontTable(headTag); 137 138 if (headTable == NULL) { 139 status = LE_MISSING_FONT_TABLE_ERROR; 140 printf("%s:%d: %s: missing head table\n", __FILE__, __LINE__, fileName); 141 goto error_exit; 142 } 143 144 fUnitsPerEM = SWAPW(headTable->unitsPerEm); 145 fFontChecksum = SWAPL(headTable->checksumAdjustment); 146 freeFontTable(headTable); 147 148 //nameTable = (NAMETable *) readFontTable(nameTag); 149 150 //if (nameTable == NULL) { 151 // status = LE_MISSING_FONT_TABLE_ERROR; 152 // goto error_exit; 153 //} 154 155 //fFontVersionString = findName(nameTable, NAME_VERSION_STRING, PLATFORM_MACINTOSH, MACINTOSH_ROMAN, MACINTOSH_ENGLISH); 156 157 //if (fFontVersionString == NULL) { 158 // status = LE_MISSING_FONT_TABLE_ERROR; 159 // goto error_exit; 160 //} 161 162 //freeFontTable(nameTable); 163 164 hheaTable = (HHEATable *) readFontTable(hheaTag); 165 166 if (hheaTable == NULL) { 167 printf("%s:%d: %s: missing hhea table\n", __FILE__, __LINE__, fileName); 168 status = LE_MISSING_FONT_TABLE_ERROR; 169 goto error_exit; 170 } 171 172 fAscent = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->ascent)); 173 fDescent = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->descent)); 174 fLeading = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->lineGap)); 175 176 fNumLongHorMetrics = SWAPW(hheaTable->numOfLongHorMetrics); 177 178 freeFontTable((void *) hheaTable); 179 180 fCMAPMapper = findUnicodeMapper(); 181 182 if (fCMAPMapper == NULL) { 183 printf("%s:%d: %s: can't load cmap\n", __FILE__, __LINE__, fileName); 184 status = LE_MISSING_FONT_TABLE_ERROR; 185 goto error_exit; 186 } 187 188 return; 189 190 error_exit: 191 fclose(fFile); 192 fFile = NULL; 193 return; 194 } 195 196 PortableFontInstance::~PortableFontInstance() 197 { 198 if (fFile != NULL) { 199 fclose(fFile); 200 201 freeFontTable(fHMTXTable); 202 freeFontTable(fNAMETable); 203 204 delete fCMAPMapper; 205 206 LE_DELETE_ARRAY(fDirectory); 207 } 208 } 209 210 const DirectoryEntry *PortableFontInstance::findTable(LETag tag) const 211 { 212 if (fDirectory != NULL) { 213 le_uint16 table = 0; 214 le_uint16 probe = fDirPower; 215 216 if (SWAPL(fDirectory->tableDirectory[fDirExtra].tag) <= tag) { 217 table = fDirExtra; 218 } 219 220 while (probe > (1 << 0)) { 221 probe >>= 1; 222 223 if (SWAPL(fDirectory->tableDirectory[table + probe].tag) <= tag) { 224 table += probe; 225 } 226 } 227 228 if (SWAPL(fDirectory->tableDirectory[table].tag) == tag) { 229 return &fDirectory->tableDirectory[table]; 230 } 231 } 232 233 return NULL; 234 } 235 236 const void *PortableFontInstance::readTable(LETag tag, le_uint32 *length) const 237 { 238 const DirectoryEntry *entry = findTable(tag); 239 240 if (entry == NULL) { 241 *length = 0; 242 return NULL; 243 } 244 245 *length = SWAPL(entry->length); 246 247 void *table = LE_NEW_ARRAY(char, *length); 248 249 if (table != NULL) { 250 fseek(fFile, SWAPL(entry->offset), SEEK_SET); 251 fread(table, sizeof(char), *length, fFile); 252 } 253 254 return table; 255 } 256 257 const void *PortableFontInstance::getFontTable(LETag tableTag) const 258 { 259 size_t ignored; 260 return getFontTable(tableTag, ignored); 261 } 262 263 const void *PortableFontInstance::getFontTable(LETag tableTag, size_t &length) const 264 { 265 return FontTableCache::find(tableTag, length); 266 } 267 268 const void *PortableFontInstance::readFontTable(LETag tableTag, size_t &length) const 269 { 270 le_uint32 len; 271 272 const void *data= readTable(tableTag, &len); 273 length = len; 274 //char tag5[5]; 275 //printf("Read %s, result %p #%d\n", letagToStr(tableTag,tag5), data,len); 276 return data; 277 } 278 279 CMAPMapper *PortableFontInstance::findUnicodeMapper() 280 { 281 LETag cmapTag = LE_CMAP_TABLE_TAG; 282 const CMAPTable *cmap = (CMAPTable *) readFontTable(cmapTag); 283 284 if (cmap == NULL) { 285 return NULL; 286 } 287 288 return CMAPMapper::createUnicodeMapper(cmap); 289 } 290 291 const char *PortableFontInstance::getNameString(le_uint16 nameID, le_uint16 platformID, le_uint16 encodingID, le_uint16 languageID) const 292 { 293 if (fNAMETable == NULL) { 294 LETag nameTag = LE_NAME_TABLE_TAG; 295 PortableFontInstance *realThis = (PortableFontInstance *) this; 296 297 realThis->fNAMETable = (const NAMETable *) readFontTable(nameTag); 298 299 if (realThis->fNAMETable != NULL) { 300 realThis->fNameCount = SWAPW(realThis->fNAMETable->count); 301 realThis->fNameStringOffset = SWAPW(realThis->fNAMETable->stringOffset); 302 } 303 } 304 305 for(le_int32 i = 0; i < fNameCount; i += 1) { 306 const NameRecord *nameRecord = &fNAMETable->nameRecords[i]; 307 308 if (SWAPW(nameRecord->platformID) == platformID && SWAPW(nameRecord->encodingID) == encodingID && 309 SWAPW(nameRecord->languageID) == languageID && SWAPW(nameRecord->nameID) == nameID) { 310 char *name = ((char *) fNAMETable) + fNameStringOffset + SWAPW(nameRecord->offset); 311 le_uint16 length = SWAPW(nameRecord->length); 312 char *result = LE_NEW_ARRAY(char, length + 2); 313 314 LE_ARRAY_COPY(result, name, length); 315 result[length] = result[length + 1] = 0; 316 317 return result; 318 } 319 } 320 321 return NULL; 322 } 323 324 const LEUnicode16 *PortableFontInstance::getUnicodeNameString(le_uint16 nameID, le_uint16 platformID, le_uint16 encodingID, le_uint16 languageID) const 325 { 326 if (fNAMETable == NULL) { 327 LETag nameTag = LE_NAME_TABLE_TAG; 328 PortableFontInstance *realThis = (PortableFontInstance *) this; 329 330 realThis->fNAMETable = (const NAMETable *) readFontTable(nameTag); 331 332 if (realThis->fNAMETable != NULL) { 333 realThis->fNameCount = SWAPW(realThis->fNAMETable->count); 334 realThis->fNameStringOffset = SWAPW(realThis->fNAMETable->stringOffset); 335 } 336 } 337 338 for(le_int32 i = 0; i < fNameCount; i += 1) { 339 const NameRecord *nameRecord = &fNAMETable->nameRecords[i]; 340 341 if (SWAPW(nameRecord->platformID) == platformID && SWAPW(nameRecord->encodingID) == encodingID && 342 SWAPW(nameRecord->languageID) == languageID && SWAPW(nameRecord->nameID) == nameID) { 343 LEUnicode16 *name = (LEUnicode16 *) (((char *) fNAMETable) + fNameStringOffset + SWAPW(nameRecord->offset)); 344 le_uint16 length = SWAPW(nameRecord->length) / 2; 345 LEUnicode16 *result = LE_NEW_ARRAY(LEUnicode16, length + 2); 346 347 for (le_int32 c = 0; c < length; c += 1) { 348 result[c] = SWAPW(name[c]); 349 } 350 351 result[length] = 0; 352 353 return result; 354 } 355 } 356 357 return NULL; 358 } 359 360 void PortableFontInstance::deleteNameString(const char *name) const 361 { 362 LE_DELETE_ARRAY(name); 363 } 364 365 void PortableFontInstance::deleteNameString(const LEUnicode16 *name) const 366 { 367 LE_DELETE_ARRAY(name); 368 } 369 370 void PortableFontInstance::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const 371 { 372 TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyph); 373 374 if (fHMTXTable == NULL) { 375 LETag maxpTag = LE_MAXP_TABLE_TAG; 376 LETag hmtxTag = LE_HMTX_TABLE_TAG; 377 const MAXPTable *maxpTable = (MAXPTable *) readFontTable(maxpTag); 378 PortableFontInstance *realThis = (PortableFontInstance *) this; 379 380 if (maxpTable != NULL) { 381 realThis->fNumGlyphs = SWAPW(maxpTable->numGlyphs); 382 freeFontTable(maxpTable); 383 } 384 385 realThis->fHMTXTable = (const HMTXTable *) readFontTable(hmtxTag); 386 } 387 388 le_uint16 index = ttGlyph; 389 390 if (ttGlyph >= fNumGlyphs || fHMTXTable == NULL) { 391 advance.fX = advance.fY = 0; 392 return; 393 } 394 395 if (ttGlyph >= fNumLongHorMetrics) { 396 index = fNumLongHorMetrics - 1; 397 } 398 399 advance.fX = xUnitsToPoints(SWAPW(fHMTXTable->hMetrics[index].advanceWidth)); 400 advance.fY = 0; 401 } 402 403 le_bool PortableFontInstance::getGlyphPoint(LEGlyphID /*glyph*/, le_int32 /*pointNumber*/, LEPoint &/*point*/) const 404 { 405 return FALSE; 406 } 407 408 le_int32 PortableFontInstance::getUnitsPerEM() const 409 { 410 return fUnitsPerEM; 411 } 412 413 le_uint32 PortableFontInstance::getFontChecksum() const 414 { 415 return fFontChecksum; 416 } 417 418 le_uint32 PortableFontInstance::getRawChecksum() const 419 { 420 // how big is it? 421 // fseek(fFile, 0L, SEEK_END); 422 // long size = ftell(fFile); 423 le_int32 chksum = 0; 424 // now, calculate 425 fseek(fFile, 0L, SEEK_SET); 426 int r; 427 int count =0; 428 while((r = fgetc(fFile)) != EOF) { 429 chksum += r; 430 count ++; 431 } 432 return (le_uint32) chksum; // cast to signed 433 } 434 435 le_int32 PortableFontInstance::getAscent() const 436 { 437 return fAscent; 438 } 439 440 le_int32 PortableFontInstance::getDescent() const 441 { 442 return fDescent; 443 } 444 445 le_int32 PortableFontInstance::getLeading() const 446 { 447 return fLeading; 448 } 449 450 // We really want to inherit this method from the superclass, but some compilers 451 // issue a warning if we don't implement it... 452 LEGlyphID PortableFontInstance::mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper, le_bool filterZeroWidth) const 453 { 454 return LEFontInstance::mapCharToGlyph(ch, mapper, filterZeroWidth); 455 } 456 457 // We really want to inherit this method from the superclass, but some compilers 458 // issue a warning if we don't implement it... 459 LEGlyphID PortableFontInstance::mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper) const 460 { 461 return LEFontInstance::mapCharToGlyph(ch, mapper); 462 } 463 464 LEGlyphID PortableFontInstance::mapCharToGlyph(LEUnicode32 ch) const 465 { 466 return fCMAPMapper->unicodeToGlyph(ch); 467 } 468 469 float PortableFontInstance::getXPixelsPerEm() const 470 { 471 return fPointSize; 472 } 473 474 float PortableFontInstance::getYPixelsPerEm() const 475 { 476 return fPointSize; 477 } 478 479 float PortableFontInstance::getScaleFactorX() const 480 { 481 return 1.0; 482 } 483 484 float PortableFontInstance::getScaleFactorY() const 485 { 486 return 1.0; 487 } 488