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