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