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 35static 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// 49le_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 85PortableFontInstance::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 190error_exit: 191 fclose(fFile); 192 fFile = NULL; 193 return; 194} 195 196PortableFontInstance::~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 210const 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 236const 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 257const void *PortableFontInstance::getFontTable(LETag tableTag) const 258{ 259 size_t ignored; 260 return getFontTable(tableTag, ignored); 261} 262 263const void *PortableFontInstance::getFontTable(LETag tableTag, size_t &length) const 264{ 265 return FontTableCache::find(tableTag, length); 266} 267 268const 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 279CMAPMapper *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 291const 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 324const 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 360void PortableFontInstance::deleteNameString(const char *name) const 361{ 362 LE_DELETE_ARRAY(name); 363} 364 365void PortableFontInstance::deleteNameString(const LEUnicode16 *name) const 366{ 367 LE_DELETE_ARRAY(name); 368} 369 370void 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 403le_bool PortableFontInstance::getGlyphPoint(LEGlyphID /*glyph*/, le_int32 /*pointNumber*/, LEPoint &/*point*/) const 404{ 405 return FALSE; 406} 407 408le_int32 PortableFontInstance::getUnitsPerEM() const 409{ 410 return fUnitsPerEM; 411} 412 413le_uint32 PortableFontInstance::getFontChecksum() const 414{ 415 return fFontChecksum; 416} 417 418le_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 435le_int32 PortableFontInstance::getAscent() const 436{ 437 return fAscent; 438} 439 440le_int32 PortableFontInstance::getDescent() const 441{ 442 return fDescent; 443} 444 445le_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... 452LEGlyphID 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... 459LEGlyphID PortableFontInstance::mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper) const 460{ 461 return LEFontInstance::mapCharToGlyph(ch, mapper); 462} 463 464LEGlyphID PortableFontInstance::mapCharToGlyph(LEUnicode32 ch) const 465{ 466 return fCMAPMapper->unicodeToGlyph(ch); 467} 468 469float PortableFontInstance::getXPixelsPerEm() const 470{ 471 return fPointSize; 472} 473 474float PortableFontInstance::getYPixelsPerEm() const 475{ 476 return fPointSize; 477} 478 479float PortableFontInstance::getScaleFactorX() const 480{ 481 return 1.0; 482} 483 484float PortableFontInstance::getScaleFactorY() const 485{ 486 return 1.0; 487} 488